Bläddra i källkod

make http size check work

Michael Vogt 11 år sedan
förälder
incheckning
a2d40703e4
100 ändrade filer med 3658 tillägg och 1995 borttagningar
  1. 0 1
      .travis.yml
  2. 1 1
      COMPILING
  3. 2 2
      Makefile
  4. 0 73
      README.ddtp
  5. 181 0
      README.md
  6. 1 1
      apt-inst/contrib/arfile.h
  7. 6 7
      apt-inst/contrib/extracttar.cc
  8. 2 2
      apt-inst/contrib/extracttar.h
  9. 2 2
      apt-inst/deb/debfile.cc
  10. 2 2
      apt-inst/deb/debfile.h
  11. 0 1
      apt-inst/dirstream.cc
  12. 2 2
      apt-inst/dirstream.h
  13. 1 1
      apt-inst/extract.cc
  14. 1 1
      apt-inst/makefile
  15. 469 201
      apt-pkg/acquire-item.cc
  16. 47 36
      apt-pkg/acquire-item.h
  17. 12 0
      apt-pkg/acquire-method.cc
  18. 1 1
      apt-pkg/acquire-method.h
  19. 26 28
      apt-pkg/acquire.cc
  20. 5 2
      apt-pkg/acquire.h
  21. 6 10
      apt-pkg/algorithms.cc
  22. 14 14
      apt-pkg/algorithms.h
  23. 29 29
      apt-pkg/aptconfiguration.cc
  24. 0 3
      apt-pkg/aptconfiguration.h
  25. 3 0
      apt-pkg/cachefile.cc
  26. 119 25
      apt-pkg/cachefilter.cc
  27. 90 27
      apt-pkg/cachefilter.h
  28. 13 3
      apt-pkg/cacheiterators.h
  29. 259 110
      apt-pkg/cacheset.cc
  30. 475 105
      apt-pkg/cacheset.h
  31. 7 3
      apt-pkg/cdrom.cc
  32. 4 1
      apt-pkg/clean.cc
  33. 11 8
      apt-pkg/contrib/cmndline.cc
  34. 0 5
      apt-pkg/contrib/configuration.cc
  35. 6 8
      apt-pkg/contrib/configuration.h
  36. 101 6
      apt-pkg/contrib/fileutl.cc
  37. 16 0
      apt-pkg/contrib/fileutl.h
  38. 18 45
      apt-pkg/contrib/gpgv.cc
  39. 2 2
      apt-pkg/contrib/hashes.cc
  40. 1 1
      apt-pkg/contrib/macros.h
  41. 86 0
      apt-pkg/contrib/proxy.cc
  42. 16 0
      apt-pkg/contrib/proxy.h
  43. 63 17
      apt-pkg/contrib/strutl.cc
  44. 4 2
      apt-pkg/contrib/strutl.h
  45. 61 35
      apt-pkg/deb/debindexfile.cc
  46. 13 12
      apt-pkg/deb/debindexfile.h
  47. 73 31
      apt-pkg/deb/deblistparser.cc
  48. 3 4
      apt-pkg/deb/deblistparser.h
  49. 1 1
      apt-pkg/deb/debmetaindex.h
  50. 2 1
      apt-pkg/deb/debsrcrecords.cc
  51. 1 1
      apt-pkg/deb/debsystem.h
  52. 158 111
      apt-pkg/deb/dpkgpm.cc
  53. 2 14
      apt-pkg/deb/dpkgpm.h
  54. 19 4
      apt-pkg/depcache.cc
  55. 7 18
      apt-pkg/depcache.h
  56. 62 10
      apt-pkg/edsp.cc
  57. 3 3
      apt-pkg/edsp.h
  58. 1 1
      apt-pkg/edsp/edspindexfile.cc
  59. 2 2
      apt-pkg/indexcopy.h
  60. 29 10
      apt-pkg/indexrecords.cc
  61. 5 1
      apt-pkg/indexrecords.h
  62. 2 0
      apt-pkg/install-progress.cc
  63. 3 4
      apt-pkg/install-progress.h
  64. 1 1
      apt-pkg/metaindex.h
  65. 49 2
      apt-pkg/packagemanager.cc
  66. 3 2
      apt-pkg/packagemanager.h
  67. 34 41
      apt-pkg/pkgcache.cc
  68. 112 122
      apt-pkg/pkgcache.h
  69. 115 140
      apt-pkg/pkgcachegen.cc
  70. 30 24
      apt-pkg/pkgcachegen.h
  71. 4 4
      apt-pkg/sourcelist.cc
  72. 0 4
      apt-pkg/sourcelist.h
  73. 24 13
      apt-pkg/srcrecords.cc
  74. 7 2
      apt-pkg/srcrecords.h
  75. 12 1
      apt-pkg/tagfile.cc
  76. 4 3
      apt-pkg/tagfile.h
  77. 2 1
      apt-pkg/update.h
  78. 79 32
      apt-pkg/upgrade.cc
  79. 9 5
      apt-pkg/upgrade.h
  80. 2 2
      apt-private/acqprogress.cc
  81. 3 1
      apt-private/private-cachefile.cc
  82. 46 43
      apt-private/private-cacheset.cc
  83. 17 20
      apt-private/private-cacheset.h
  84. 7 2
      apt-private/private-cmndline.cc
  85. 5 0
      apt-private/private-download.cc
  86. 6 0
      apt-private/private-download.h
  87. 159 9
      apt-private/private-install.cc
  88. 9 151
      apt-private/private-install.h
  89. 18 23
      apt-private/private-list.cc
  90. 205 172
      apt-private/private-output.cc
  91. 4 3
      apt-private/private-output.h
  92. 58 24
      apt-private/private-search.cc
  93. 4 4
      apt-private/private-show.cc
  94. 29 1
      apt-private/private-update.cc
  95. 3 13
      apt-private/private-upgrade.cc
  96. 41 17
      apt-private/private-utils.cc
  97. 2 2
      apt-private/private-utils.h
  98. 4 0
      buildlib/config.h.in
  99. 0 60
      buildlib/debiandoc.mak
  100. 0 0
      buildlib/defaults.mak

+ 0 - 1
.travis.yml

@@ -2,5 +2,4 @@ language: cpp
 before_install:
  - sudo apt-get update -q
  - sudo ./prepare-release travis-ci
- - sudo apt-get install -q --no-install-recommends stunnel4
 script: make && make test && test/integration/run-tests

+ 1 - 1
COMPILING

@@ -53,7 +53,7 @@ Debian GNU Linux 'potato'
 Debian GNU Linux 'woody'
   * All Archs
   - Works flawlessly
-  - You will want to have debiandoc-sgml and docbook2man installed to get
+  - You will want to have docbook-xml and docbook2man installed to get
     best results.
   - No IPv6 Support in glibc's < 2.1.
 

+ 2 - 2
Makefile

@@ -10,7 +10,7 @@ endif
 default: startup all
 
 .PHONY: headers library clean veryclean all binary program doc test update-po
-all headers library clean veryclean binary program doc manpages debiandoc test update-po startup dirs:
+all headers library clean veryclean binary program doc manpages docbook test update-po startup dirs:
 	$(MAKE) -C vendor $@
 	$(MAKE) -C apt-pkg $@
 	$(MAKE) -C apt-inst $@
@@ -23,7 +23,7 @@ all headers library clean veryclean binary program doc manpages debiandoc test u
 	$(MAKE) -C po $@
 	$(MAKE) -C test $@
 
-all headers library clean veryclean binary program doc manpages debiandoc test update-po: startup dirs
+all headers library clean veryclean binary program doc manpages docbook test update-po: startup dirs
 
 dirs: startup
 

+ 0 - 73
README.ddtp

@@ -1,74 +0,0 @@
-TODO:
-- URL-Remap for the translation files (to hack around the problem that
-  they are not on any ftp server yet but only on http://ddtp.debian.org/)
-
-Here is the original announcement of the ddtp support:
-
-* To: debian-devel-announce@lists.debian.org
-* Subject: Translate files
-* From: Michael Bramer <grisu@debian.org>
-* Date: Sun, 6 Oct 2002 21:56:06 +0200
-* Mail-followup-to: debian-devel@lists.debian.org
-* Message-id: <20021006195605.GA30516@home.debsupport.de>
-* Old-return-path: <michael@home.debsupport.de>
-* User-agent: Mutt/1.3.28i
-
-Hello all
-
-After some discussion between Anthony Towns (a ftpmaster), Jason
-Gunthorpe (APT Developer) and some DDTP Coordinators we find a way to
-transfer the translated package descriptions from the archive to the
-user. 
-
-The translated descriptions need to be downloadable befor any
-installation process, like the other package meta information. We
-choose a new file per languages with all translated package
-descriptions. The package system can download one or more of this
-files at 'apt-get update' time and know the translations.
-
-The new files are names 'Translate-$lang' and the file have this
-rfc822-format:
-  Package: &lt;package-name&gt;
-  Description-md5: &lt;the md5 checksum of the english description&gt;
-  Description-$lang.$encoding: &lt;translated headline&gt;
-   &lt;translated section&gt;
-
-The encoding of the Description is 'UTF-8' in all languages normal.
-The files will be located at 'debian/dists/sid/main/i18n/' on the ftp
-server (for all architecture). In addition of the plain
-'Translate-$lang' file, there will be a 'gz' and a 'bz2' version and
-in future also the new incremental format version.
-
-The &lt;the md5 checksum of the english description&gt; is the md5 checksum
-of the full english description, without the 'Description: '-tag and
-with all spaces and newlines. Look at this example:
- Description: XXX
-  YYY
-  .
-  ZZZ
-is md5(&quot;XXX\n YYY\n .\n ZZZ\n&quot;) (perl-syntax).
-
-
-A future APT version will download one or some 'Translate-$lang'
-file(s) at 'update'-time. After this download it show a translated
-description instead of the english form, if it found a translated
-description of the package with the right md5 chechsum. The environment
-of the user will controlled this process (LANG, LANGUAGE, LC_MESSAGES,
-etc). With this the package system will never show a outdated
-translation.
-
-The translations come all from the DDTP. A daily process on
-ddtp.debian.org make new 'Translated-$lang' files and a script on
-ftp-master request this files and move this to the debian archive.
-Now the first files are accessible at
-	<a  href="http://ddtp.debian.org/pdesc/translatefiles/">http://ddtp.debian.org/pdesc/translatefiles/</a>
-
-If you found wrong translations, please read the guides on
-ddtp.debian.org, make a better translation and send this per mail to
-the DDTP server. Don't bug the package maintainer!
-
-Thanks
-Grisu
-Michael Bramer  -  a Debian Linux Developer      <a  href="http://www.debsupport.de">http://www.debsupport.de</a>
-PGP: finger grisu@db.debian.org  -- Linux Sysadmin   -- Use Debian Linux

+ 181 - 0
README.md

@@ -0,0 +1,181 @@
+APT
+===
+
+apt is the main commandline package manager for Debian and its derivatives.
+It provides commandline tools for searching and managing as well as querying
+information about packages as well as low-level access to all features
+provided by the libapt-pkg and libapt-inst libraries which higher-level
+package managers can depend upon.
+
+Included tools are:
+
+* apt-get for retrieval of packages and information about them
+  from authenticated sources and for installation, upgrade and
+  removal of packages together with their dependencies
+* apt-cache for querying available information about installed
+  as well as installable packages
+* apt-cdrom to use removable media as a source for packages
+* apt-config as an interface to the configuration settings
+* apt-key as an interface to manage authentication keys
+* apt-extracttemplates to be used by debconf to prompt for configuration
+  questions before installation.
+* apt-ftparchive creates Packages and other index files
+  needed to publish an archive of debian packages
+* apt-sortpkgs is a Packages/Sources file normalizer.
+
+The libraries libapt-pkg and libapt-inst are also maintained as part of this project,
+alongside various additional binaries like the acquire-methods used by them.
+Bindings for Python ([python-apt](https://tracker.debian.org/pkg/python-apt)) and
+Perl ([libapt-pkg-perl](https://tracker.debian.org/pkg/libapt-pkg-perl)) are available as separated projects.
+
+Discussion happens mostly on [the mailinglist](mailto:deity@lists.debian.org) ([archive](https://lists.debian.org/deity/)) and on [IRC](irc://irc.oftc.net/debian-apt).
+Our bugtracker as well as a general overview can be found at the [Debian Tracker page](https://tracker.debian.org/pkg/apt).
+
+
+Contributing
+------------
+APT is maintained in git, the official repository being located at
+`git://anonscm.debian.org/apt/apt.git` ([webgit](http://anonscm.debian.org/gitweb/?p=apt/apt.git)),
+but also available at other locations like [GitHub](https://github.com/Debian/apt).
+
+The default branch is `debian/sid`, other branches targeted at different
+derivatives and releases being used as needed. Various topic branches in
+different stages of completion might be branched of from those, which you
+are encouraged to do as well.
+
+### Coding
+
+APT uses its own autoconf based build system, see [README.make](http://anonscm.debian.org/gitweb/?p=apt/apt.git;a=blob;f=README.make)
+for the glory details, but to get started, just run:
+
+	$ make
+
+from a fresh git checkout.
+
+The source code uses in most parts a relatively uncommon indent convention,
+namely 3 spaces with 8 space tab (see [doc/style.txt](http://anonscm.debian.org/gitweb/?p=apt/apt.git;a=blob;f=doc/style.txt) for more on this).
+Adhering to it avoids unnecessary code-churn destroying history (aka: `git blame`)
+and you are therefore encouraged to write patches in this style.
+Your editor can surely help you with this, for vim the settings would be
+`setlocal shiftwidth=3 noexpandtab tabstop=8`
+(the later two are the default configuration and could therefore be omitted).
+
+### Translations
+
+While we welcome contributions here, we highly encourage you to contact the [Debian Internationalization (i18n) team](https://wiki.debian.org/Teams/I18n).
+Various language teams have formed which can help you creating, maintaining
+and improving a translation, while we could only do a basic syntax check of the
+file format…
+
+Further more, Translating APT is split into two independent parts:
+The program translation, meaning the messages printed by the tools,
+as well as the manpages and other documentation shipped with APT.
+
+### Bug triage
+
+Software tools like APT which are used by thousands of users every
+day have a steady flow of incoming bugreports. Not all of them are really
+bugs in APT: It can be packaging bugs like failing maintainer scripts a
+user reports against apt, because apt was the command he executed leading
+to this failure or various wishlist items for new features. Given enough time
+also the occasional duplicate enters the system.
+Our bugtracker is therefore full with open bugreports which are waiting for you! ;)
+
+Testing
+-------
+
+### Manual execution
+
+When you make changes and want to run them manually, make sure your
+`$LD_LIBRARY_PATH` points to the libraries you have built, e.g. via:
+
+	$ export LD_LIBRARY_PATH=$(pwd)/build/bin
+	$ ./build/bin/apt-get moo
+
+
+### Integration tests
+
+There is a extensive integration testsuite available which can be run via:
+
+	$ ./test/integration/run-tests
+
+While these tests are not executed at package build-time as they require additional
+dependencies, the repository contains the configuration needed to run them on [Travis CI](https://travis-ci.org/)
+as well as via autopkgtests e.g. on [Debian Continuous Integration](http://ci.debian.net/?q=apt#package/apt).
+
+A testcase here is a shellscript embedded in a framework creating an environment in which
+apt tools can be used naturally without root-rights to test every aspect of its behavior
+itself as well as in conjunction with dpkg and other tools while working with packages.
+
+
+### Unit tests
+
+These tests are gtest-dev based, reside in `./test/libapt` and can be run with `make test`.
+They are executed at package build-time, but not by `make`.
+
+Debugging
+---------
+
+APT does many things, so there is no central debug mode which could be
+activated. It uses instead various config-options to activate debug output
+in certain areas. The following describes some common scenarios and generally
+useful options, but is in no way exhaustive.
+
+Note that you should *NEVER* use these settings as root to avoid accidents.
+Similation mode (`-s`) is usually sufficient to help you run apt as a non-root user.
+
+### Using different state files
+
+If a dependency solver bug is reported, but can't be reproduced by the
+triager easily, it is beneficial to ask the reporter for the
+`/var/lib/dpkg/status` file, which includes the packages installed on the
+system and in which version. Such a file can then be used via the option
+`dir::state::status`. Beware of different architecture settings!
+Bugreports usually include this information in the template. Assuming you
+already have the `Packages` files for the architecture (see `sources.list`
+manpage for the `arch=` option) you can change to a different architecture
+with a config file like:
+
+	APT::Architecture "arch1";
+	#clear APT::Architectures;
+	APT:: Architectures { "arch1"; "arch2"; }
+
+If a certain mirror state is needed, see if you can reproduce it with [snapshot.debian.org](http://snapshot.debian.org/).
+Your sources.list file (`dir::etc::sourcelist`) has to be correctly mention the repository,
+but if it does, you can use different downloaded archive state files via `dir::state::lists`.
+
+In case manually vs. automatically installed matters, you can ask the reporter for
+the `/var/lib/apt/extended_states` file and use it with `dir::state::extended_states`.
+
+### Dependency resolution
+
+APT works in its internal resolver in two stages: First all packages are visited
+and marked for installation, keep back or removal. Option `Debug::pkgDepCache::Marker`
+shows this. This also decides which packages are to be installed to satisfy dependencies,
+which can be seen by `Debug::pkgDepCache::AutoInstall`. After this is done, we might
+be in a situation in which two packages want to be installed, but only on of them can be.
+It is the job of the pkgProblemResolver to decide which of two packages 'wins' and can
+therefore decide what has to happen. You can see the contenders as well as their fight and
+the resulting resolution with `Debug::pkgProblemResolver`.
+
+### Downloading files
+
+Various binaries (called 'methods') are tasked with downloading files. The Acquire system
+talks to them via simple text protocol. Depending on which side you want to see, either
+`Debug::pkgAcquire::Worker` or `Debug::Acquire::http` (or similar) will show the messages.
+
+The integration tests use a simple self-built webserver which also logs. If you find that
+the http(s) methods do not behave like they should be try to implement this behavior in the
+webserver for simpler and more controlled testing.
+
+### Installation order
+
+Dependencies are solved, packages downloaded: Everything read for the installation!
+The last step in the chain is often forgotten, but still very important:
+Packages have to be installed in a particular order so that their dependencies are
+satisfied, but at the same time you don't want to install very important and optional
+packages at the same time if possible, so that a broken optional package does not
+block the correct installation of very important packages. Which option to use depends on
+if you are interested in the topology sorting (`Debug::pkgOrderList`), the dependency-aware
+cycle and unconfigured prevention (`Debug::pkgPackageManager`) or the actual calls
+to dpkg (`Debug::pkgDpkgPm`).

+ 1 - 1
apt-inst/contrib/arfile.h

@@ -61,7 +61,7 @@ struct ARArchive::Member
    unsigned long long Size;
    
    // Location of the data.
-   unsigned long Start;
+   unsigned long long Start;
    Member *Next;
    
    Member() : Start(0), Next(0) {};

+ 6 - 7
apt-inst/contrib/extracttar.cc

@@ -60,9 +60,8 @@ struct ExtractTar::TarHeader
 // ExtractTar::ExtractTar - Constructor					/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-ExtractTar::ExtractTar(FileFd &Fd,unsigned long Max,string DecompressionProgram) : File(Fd), 
-                         MaxInSize(Max), DecompressProg(DecompressionProgram)
-
+ExtractTar::ExtractTar(FileFd &Fd,unsigned long long Max,string DecompressionProgram)
+	: File(Fd), MaxInSize(Max), DecompressProg(DecompressionProgram)
 {
    GZPid = -1;
    Eof = false;
@@ -267,7 +266,7 @@ bool ExtractTar::Go(pkgDirStream &Stream)
 
 	 case GNU_LongLink:
 	 {
-	    unsigned long Length = Itm.Size;
+	    unsigned long long Length = Itm.Size;
 	    unsigned char Block[512];
 	    while (Length > 0)
 	    {
@@ -286,7 +285,7 @@ bool ExtractTar::Go(pkgDirStream &Stream)
 	 
 	 case GNU_LongName:
 	 {
-	    unsigned long Length = Itm.Size;
+	    unsigned long long Length = Itm.Size;
 	    unsigned char Block[512];
 	    while (Length > 0)
 	    {
@@ -315,11 +314,11 @@ bool ExtractTar::Go(pkgDirStream &Stream)
 	    return false;
       
       // Copy the file over the FD
-      unsigned long Size = Itm.Size;
+      unsigned long long Size = Itm.Size;
       while (Size != 0)
       {
 	 unsigned char Junk[32*1024];
-	 unsigned long Read = min(Size,(unsigned long)sizeof(Junk));
+	 unsigned long Read = min(Size, (unsigned long long)sizeof(Junk));
 	 if (InFd.Read(Junk,((Read+511)/512)*512) == false)
 	    return false;
 	 

+ 2 - 2
apt-inst/contrib/extracttar.h

@@ -39,7 +39,7 @@ class ExtractTar
                   GNU_LongLink = 'K',GNU_LongName = 'L'};
 
    FileFd &File;
-   unsigned long MaxInSize;
+   unsigned long long MaxInSize;
    int GZPid;
    FileFd InFd;
    bool Eof;
@@ -53,7 +53,7 @@ class ExtractTar
 
    bool Go(pkgDirStream &Stream);
    
-   ExtractTar(FileFd &Fd,unsigned long Max,std::string DecompressionProgram);
+   ExtractTar(FileFd &Fd,unsigned long long Max,std::string DecompressionProgram);
    virtual ~ExtractTar();
 };
 

+ 2 - 2
apt-inst/deb/debfile.cc

@@ -203,7 +203,7 @@ bool debDebFile::MemControlExtract::DoItem(Item &Itm,int &Fd)
 /* Just memcopy the block from the tar extractor and put it in the right
    place in the pre-allocated memory block. */
 bool debDebFile::MemControlExtract::Process(Item &/*Itm*/,const unsigned char *Data,
-			     unsigned long Size,unsigned long Pos)
+			     unsigned long long Size,unsigned long long Pos)
 {
    memcpy(Control + Pos, Data,Size);
    return true;
@@ -232,7 +232,7 @@ bool debDebFile::MemControlExtract::Read(debDebFile &Deb)
 // ---------------------------------------------------------------------
 /* The given memory block is loaded into the parser and parsed as a control
    record. */
-bool debDebFile::MemControlExtract::TakeControl(const void *Data,unsigned long Size)
+bool debDebFile::MemControlExtract::TakeControl(const void *Data,unsigned long long Size)
 {
    delete [] Control;
    Control = new char[Size+2];

+ 2 - 2
apt-inst/deb/debfile.h

@@ -81,12 +81,12 @@ class debDebFile::MemControlExtract : public pkgDirStream
    // Members from DirStream
    virtual bool DoItem(Item &Itm,int &Fd);
    virtual bool Process(Item &Itm,const unsigned char *Data,
-			unsigned long Size,unsigned long Pos);
+			unsigned long long Size,unsigned long long Pos);
    
 
    // Helpers
    bool Read(debDebFile &Deb);
-   bool TakeControl(const void *Data,unsigned long Size);
+   bool TakeControl(const void *Data,unsigned long long Size);
       
    MemControlExtract() : IsControl(false), Control(0), Length(0), Member("control") {};
    MemControlExtract(std::string Member) : IsControl(false), Control(0), Length(0), Member(Member) {};

+ 0 - 1
apt-inst/dirstream.cc

@@ -76,7 +76,6 @@ bool pkgDirStream::DoItem(Item &Itm,int &Fd)
 	 if(mkdir(Itm.Name,Itm.Mode) < 0)
 	    return false;
 	 return true;
-	 break;
       }
       case Item::FIFO:
       break;

+ 2 - 2
apt-inst/dirstream.h

@@ -37,10 +37,10 @@ class pkgDirStream
 	           Directory, FIFO} Type;
       char *Name;
       char *LinkTarget;
+      unsigned long long Size;
       unsigned long Mode;
       unsigned long UID;
       unsigned long GID;
-      unsigned long Size;
       unsigned long MTime;
       unsigned long Major;
       unsigned long Minor;
@@ -50,7 +50,7 @@ class pkgDirStream
    virtual bool Fail(Item &Itm,int Fd);
    virtual bool FinishedFile(Item &Itm,int Fd);
    virtual bool Process(Item &/*Itm*/,const unsigned char * /*Data*/,
-			unsigned long /*Size*/,unsigned long /*Pos*/) {return true;};
+			unsigned long long /*Size*/,unsigned long long /*Pos*/) {return true;};
       
    virtual ~pkgDirStream() {};   
 };

+ 1 - 1
apt-inst/extract.cc

@@ -404,7 +404,7 @@ bool pkgExtract::HandleOverwrites(pkgFLCache::NodeIterator Nde,
       // Now see if this package matches one in a replace depends
       pkgCache::DepIterator Dep = Ver.DependsList();
       bool Ok = false;
-      for (; Dep.end() == false; Dep++)
+      for (; Dep.end() == false; ++Dep)
       {
 	 if (Dep->Type != pkgCache::Dep::Replaces)
 	    continue;

+ 1 - 1
apt-inst/makefile

@@ -14,7 +14,7 @@ include ../buildlib/libversion.mak
 
 # The library name
 LIBRARY=apt-inst
-MAJOR=1.5
+MAJOR=1.6
 MINOR=0
 SLIBS=$(PTHREADLIB) -lapt-pkg
 APT_DOMAIN:=libapt-inst$(MAJOR)

+ 469 - 201
apt-pkg/acquire-item.cc

@@ -64,6 +64,10 @@ static void printHashSumComparision(std::string const &URI, HashStringList const
 									/*}}}*/
 
 // Acquire::Item::Item - Constructor					/*{{{*/
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic push
+	#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
 pkgAcquire::Item::Item(pkgAcquire *Owner, HashStringList const &ExpectedHashes) :
    Owner(Owner), FileSize(0), PartialSize(0), Mode(0), ID(0), Complete(false),
    Local(false), QueueCounter(0), ExpectedAdditionalItems(0),
@@ -72,6 +76,9 @@ pkgAcquire::Item::Item(pkgAcquire *Owner, HashStringList const &ExpectedHashes)
    Owner->Add(this);
    Status = StatIdle;
 }
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic pop
+#endif
 									/*}}}*/
 // Acquire::Item::~Item - Destructor					/*{{{*/
 // ---------------------------------------------------------------------
@@ -369,7 +376,7 @@ pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire *Owner,
    Desc.URI = Target->URI + ".diff/Index";
 
    DestFile = _config->FindDir("Dir::State::lists") + "partial/";
-   DestFile += URItoFileName(Target->URI) + string(".DiffIndex");
+   DestFile += URItoFileName(Desc.URI);
 
    if(Debug)
       std::clog << "pkgAcqDiffIndex: " << Desc.URI << std::endl;
@@ -385,9 +392,7 @@ pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire *Owner,
       Desc.URI.substr(0,strlen("file:/")) == "file:/")
    {
       // we don't have a pkg file or we don't want to queue
-      if(Debug)
-	 std::clog << "No index file, local or canceld by user" << std::endl;
-      Failed("", NULL);
+      Failed("No index file, local or canceld by user", NULL);
       return;
    }
 
@@ -405,7 +410,7 @@ pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire *Owner,
 string pkgAcqDiffIndex::Custom600Headers() const
 {
    string Final = _config->FindDir("Dir::State::lists");
-   Final += URItoFileName(RealURI) + string(".IndexDiff");
+   Final += URItoFileName(Desc.URI);
    
    if(Debug)
       std::clog << "Custom600Header-IMS: " << Final << std::endl;
@@ -419,156 +424,264 @@ string pkgAcqDiffIndex::Custom600Headers() const
 									/*}}}*/
 bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile)		/*{{{*/
 {
+   // failing here is fine: our caller will take care of trying to
+   // get the complete file if patching fails
    if(Debug)
       std::clog << "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
 	 << std::endl;
 
-   pkgTagSection Tags;
-   string ServerSha1;
-   vector<DiffInfo> available_patches;
-   
    FileFd Fd(IndexDiffFile,FileFd::ReadOnly);
    pkgTagFile TF(&Fd);
    if (_error->PendingError() == true)
       return false;
 
-   if(TF.Step(Tags) == true)
+   pkgTagSection Tags;
+   if(unlikely(TF.Step(Tags) == false))
+      return false;
+
+   HashStringList ServerHashes;
+   unsigned long long ServerSize = 0;
+
+   for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type)
    {
-      bool found = false;
-      DiffInfo d;
-      string size;
+      std::string tagname = *type;
+      tagname.append("-Current");
+      std::string const tmp = Tags.FindS(tagname.c_str());
+      if (tmp.empty() == true)
+	 continue;
 
-      string const tmp = Tags.FindS("SHA1-Current");
+      string hash;
+      unsigned long long size;
       std::stringstream ss(tmp);
-      ss >> ServerSha1 >> size;
-      unsigned long const ServerSize = atol(size.c_str());
+      ss >> hash >> size;
+      if (unlikely(hash.empty() == true))
+	 continue;
+      if (unlikely(ServerSize != 0 && ServerSize != size))
+	 continue;
+      ServerHashes.push_back(HashString(*type, hash));
+      ServerSize = size;
+   }
 
-      FileFd fd(CurrentPackagesFile, FileFd::ReadOnly);
-      SHA1Summation SHA1;
-      SHA1.AddFD(fd);
-      string const local_sha1 = SHA1.Result();
+   if (ServerHashes.usable() == false)
+   {
+      if (Debug == true)
+	 std::clog << "pkgAcqDiffIndex: " << IndexDiffFile << ": Did not find a good hashsum in the index" << std::endl;
+      return false;
+   }
 
-      if(local_sha1 == ServerSha1)
-      {
-	 // we have the same sha1 as the server so we are done here
-	 if(Debug)
-	    std::clog << "Package file is up-to-date" << std::endl;
-	 // list cleanup needs to know that this file as well as the already
-	 // present index is ours, so we create an empty diff to save it for us
-	 new pkgAcqIndexDiffs(Owner, Target, ExpectedHashes, MetaIndexParser, 
-                              ServerSha1, available_patches);
-	 return true;
-      }
-      else
+   if (ServerHashes != HashSums())
+   {
+      if (Debug == true)
+	 std::clog << "pkgAcqDiffIndex: " << IndexDiffFile << ": Index has different hashes than parser, probably older, so fail pdiffing" << std::endl;
+      return false;
+   }
+
+   if (ServerHashes.VerifyFile(CurrentPackagesFile) == true)
+   {
+      // we have the same sha1 as the server so we are done here
+      if(Debug)
+	 std::clog << "pkgAcqDiffIndex: Package file is up-to-date" << std::endl;
+      // list cleanup needs to know that this file as well as the already
+      // present index is ours, so we create an empty diff to save it for us
+      new pkgAcqIndexDiffs(Owner, Target, ExpectedHashes, MetaIndexParser);
+      return true;
+   }
+
+   FileFd fd(CurrentPackagesFile, FileFd::ReadOnly);
+   Hashes LocalHashesCalc;
+   LocalHashesCalc.AddFD(fd);
+   HashStringList const LocalHashes = LocalHashesCalc.GetHashStringList();
+
+   if(Debug)
+      std::clog << "Server-Current: " << ServerHashes.find(NULL)->toStr() << " and we start at "
+	 << fd.Name() << " " << fd.FileSize() << " " << LocalHashes.find(NULL)->toStr() << std::endl;
+
+   // parse all of (provided) history
+   vector<DiffInfo> available_patches;
+   bool firstAcceptedHashes = true;
+   for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type)
+   {
+      if (LocalHashes.find(*type) == NULL)
+	 continue;
+
+      std::string tagname = *type;
+      tagname.append("-History");
+      std::string const tmp = Tags.FindS(tagname.c_str());
+      if (tmp.empty() == true)
+	 continue;
+
+      string hash, filename;
+      unsigned long long size;
+      std::stringstream ss(tmp);
+
+      while (ss >> hash >> size >> filename)
       {
-	 if(Debug)
-	    std::clog << "SHA1-Current: " << ServerSha1 << " and we start at "<< fd.Name() << " " << fd.Size() << " " << local_sha1 << std::endl;
+	 if (unlikely(hash.empty() == true || filename.empty() == true))
+	    continue;
 
-	 // check the historie and see what patches we need
-	 string const history = Tags.FindS("SHA1-History");
-	 std::stringstream hist(history);
-	 while(hist >> d.sha1 >> size >> d.file)
+	 // see if we have a record for this file already
+	 std::vector<DiffInfo>::iterator cur = available_patches.begin();
+	 for (; cur != available_patches.end(); ++cur)
 	 {
-	    // read until the first match is found
-	    // from that point on, we probably need all diffs
-	    if(d.sha1 == local_sha1) 
-	       found=true;
-	    else if (found == false)
+	    if (cur->file != filename || unlikely(cur->result_size != size))
 	       continue;
-
-	    if(Debug)
-	       std::clog << "Need to get diff: " << d.file << std::endl;
-	    available_patches.push_back(d);
+	    cur->result_hashes.push_back(HashString(*type, hash));
+	    break;
 	 }
-
-	 if (available_patches.empty() == false)
+	 if (cur != available_patches.end())
+	    continue;
+	 if (firstAcceptedHashes == true)
 	 {
-	    // patching with too many files is rather slow compared to a fast download
-	    unsigned long const fileLimit = _config->FindI("Acquire::PDiffs::FileLimit", 0);
-	    if (fileLimit != 0 && fileLimit < available_patches.size())
-	    {
-	       if (Debug)
-		  std::clog << "Need " << available_patches.size() << " diffs (Limit is " << fileLimit
-			<< ") so fallback to complete download" << std::endl;
-	       return false;
-	    }
-
-	    // see if the patches are too big
-	    found = false; // it was true and it will be true again at the end
-	    d = *available_patches.begin();
-	    string const firstPatch = d.file;
-	    unsigned long patchesSize = 0;
-	    std::stringstream patches(Tags.FindS("SHA1-Patches"));
-	    while(patches >> d.sha1 >> size >> d.file)
-	    {
-	       if (firstPatch == d.file)
-		  found = true;
-	       else if (found == false)
-		  continue;
-
-	       patchesSize += atol(size.c_str());
-	    }
-	    unsigned long const sizeLimit = ServerSize * _config->FindI("Acquire::PDiffs::SizeLimit", 100);
-	    if (sizeLimit > 0 && (sizeLimit/100) < patchesSize)
-	    {
-	       if (Debug)
-		  std::clog << "Need " << patchesSize << " bytes (Limit is " << sizeLimit/100
-			<< ") so fallback to complete download" << std::endl;
-	       return false;
-	    }
+	    DiffInfo next;
+	    next.file = filename;
+	    next.result_hashes.push_back(HashString(*type, hash));
+	    next.result_size = size;
+	    next.patch_size = 0;
+	    available_patches.push_back(next);
+	 }
+	 else
+	 {
+	    if (Debug == true)
+	       std::clog << "pkgAcqDiffIndex: " << IndexDiffFile << ": File " << filename
+		  << " wasn't in the list for the first parsed hash! (history)" << std::endl;
+	    break;
 	 }
       }
+      firstAcceptedHashes = false;
+   }
+
+   if (unlikely(available_patches.empty() == true))
+   {
+      if (Debug)
+	 std::clog << "pkgAcqDiffIndex: " << IndexDiffFile << ": "
+	    << "Couldn't find any patches for the patch series." << std::endl;
+      return false;
+   }
+
+   for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type)
+   {
+      if (LocalHashes.find(*type) == NULL)
+	 continue;
+
+      std::string tagname = *type;
+      tagname.append("-Patches");
+      std::string const tmp = Tags.FindS(tagname.c_str());
+      if (tmp.empty() == true)
+	 continue;
 
-      // we have something, queue the next diff
-      if(found)
+      string hash, filename;
+      unsigned long long size;
+      std::stringstream ss(tmp);
+
+      while (ss >> hash >> size >> filename)
       {
-	 // queue the diffs
-	 string::size_type const last_space = Description.rfind(" ");
-	 if(last_space != string::npos)
-	    Description.erase(last_space, Description.size()-last_space);
-
-	 /* decide if we should download patches one by one or in one go:
-	    The first is good if the server merges patches, but many don't so client
-	    based merging can be attempt in which case the second is better.
-	    "bad things" will happen if patches are merged on the server,
-	    but client side merging is attempt as well */
-	 bool pdiff_merge = _config->FindB("Acquire::PDiffs::Merge", true);
-	 if (pdiff_merge == true)
-	 {
-	    // reprepro adds this flag if it has merged patches on the server
-	    std::string const precedence = Tags.FindS("X-Patch-Precedence");
-	    pdiff_merge = (precedence != "merged");
-	 }
+	 if (unlikely(hash.empty() == true || filename.empty() == true))
+	    continue;
 
-	 if (pdiff_merge == false)
-         {
-	    new pkgAcqIndexDiffs(Owner, Target, ExpectedHashes, MetaIndexParser,
-                                 ServerSha1, available_patches);
-         }
-         else
+	 // see if we have a record for this file already
+	 std::vector<DiffInfo>::iterator cur = available_patches.begin();
+	 for (; cur != available_patches.end(); ++cur)
 	 {
-	    std::vector<pkgAcqIndexMergeDiffs*> *diffs = new std::vector<pkgAcqIndexMergeDiffs*>(available_patches.size());
-	    for(size_t i = 0; i < available_patches.size(); ++i)
-	       (*diffs)[i] = new pkgAcqIndexMergeDiffs(Owner, Target,
-                                                       ExpectedHashes,
-                                                       MetaIndexParser,
-                                                       available_patches[i],
-                                                       diffs);
+	    if (cur->file != filename)
+	       continue;
+	    if (unlikely(cur->patch_size != 0 && cur->patch_size != size))
+	       continue;
+	    cur->patch_hashes.push_back(HashString(*type, hash));
+	    cur->patch_size = size;
+	    break;
 	 }
-
-	 Complete = false;
-	 Status = StatDone;
-	 Dequeue();
-	 return true;
+	 if (cur != available_patches.end())
+	       continue;
+	 if (Debug == true)
+	    std::clog << "pkgAcqDiffIndex: " << IndexDiffFile << ": File " << filename
+	       << " wasn't in the list for the first parsed hash! (patches)" << std::endl;
+	 break;
       }
    }
-   
-   // Nothing found, report and return false
-   // Failing here is ok, if we return false later, the full
-   // IndexFile is queued
-   if(Debug)
-      std::clog << "Can't find a patch in the index file" << std::endl;
-   return false;
+
+   bool foundStart = false;
+   for (std::vector<DiffInfo>::iterator cur = available_patches.begin();
+	 cur != available_patches.end(); ++cur)
+   {
+      if (LocalHashes != cur->result_hashes)
+	 continue;
+
+      available_patches.erase(available_patches.begin(), cur);
+      foundStart = true;
+      break;
+   }
+
+   if (foundStart == false || unlikely(available_patches.empty() == true))
+   {
+      if (Debug)
+	 std::clog << "pkgAcqDiffIndex: " << IndexDiffFile << ": "
+	    << "Couldn't find the start of the patch series." << std::endl;
+      return false;
+   }
+
+   // patching with too many files is rather slow compared to a fast download
+   unsigned long const fileLimit = _config->FindI("Acquire::PDiffs::FileLimit", 0);
+   if (fileLimit != 0 && fileLimit < available_patches.size())
+   {
+      if (Debug)
+	 std::clog << "Need " << available_patches.size() << " diffs (Limit is " << fileLimit
+	    << ") so fallback to complete download" << std::endl;
+      return false;
+   }
+
+   // calculate the size of all patches we have to get
+   // note that all sizes are uncompressed, while we download compressed files
+   unsigned long long patchesSize = 0;
+   for (std::vector<DiffInfo>::const_iterator cur = available_patches.begin();
+	 cur != available_patches.end(); ++cur)
+      patchesSize += cur->patch_size;
+   unsigned long long const sizeLimit = ServerSize * _config->FindI("Acquire::PDiffs::SizeLimit", 100);
+   if (false && sizeLimit > 0 && (sizeLimit/100) < patchesSize)
+   {
+      if (Debug)
+	 std::clog << "Need " << patchesSize << " bytes (Limit is " << sizeLimit/100
+	    << ") so fallback to complete download" << std::endl;
+      return false;
+   }
+
+   // we have something, queue the diffs
+   string::size_type const last_space = Description.rfind(" ");
+   if(last_space != string::npos)
+      Description.erase(last_space, Description.size()-last_space);
+
+   /* decide if we should download patches one by one or in one go:
+      The first is good if the server merges patches, but many don't so client
+      based merging can be attempt in which case the second is better.
+      "bad things" will happen if patches are merged on the server,
+      but client side merging is attempt as well */
+   bool pdiff_merge = _config->FindB("Acquire::PDiffs::Merge", true);
+   if (pdiff_merge == true)
+   {
+      // reprepro adds this flag if it has merged patches on the server
+      std::string const precedence = Tags.FindS("X-Patch-Precedence");
+      pdiff_merge = (precedence != "merged");
+   }
+
+   if (pdiff_merge == false)
+   {
+      new pkgAcqIndexDiffs(Owner, Target, ExpectedHashes, MetaIndexParser,
+	    available_patches);
+   }
+   else
+   {
+      std::vector<pkgAcqIndexMergeDiffs*> *diffs = new std::vector<pkgAcqIndexMergeDiffs*>(available_patches.size());
+      for(size_t i = 0; i < available_patches.size(); ++i)
+	 (*diffs)[i] = new pkgAcqIndexMergeDiffs(Owner, Target,
+	       ExpectedHashes,
+	       MetaIndexParser,
+	       available_patches[i],
+	       diffs);
+   }
+
+   Complete = false;
+   Status = StatDone;
+   Dequeue();
+   return true;
 }
 									/*}}}*/
 void pkgAcqDiffIndex::Failed(string Message,pkgAcquire::MethodConfig * /*Cnf*/)/*{{{*/
@@ -606,7 +719,7 @@ void pkgAcqDiffIndex::Done(string Message,unsigned long long Size,HashStringList
    DestFile = FinalFile;
 
    if(!ParseDiffIndex(DestFile))
-      return Failed("", NULL);
+      return Failed("Parsing pdiff Index failed", NULL);
 
    Complete = true;
    Status = StatDone;
@@ -623,12 +736,10 @@ pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire *Owner,
                                    struct IndexTarget const * const Target,
                                    HashStringList const &ExpectedHashes,
                                    indexRecords *MetaIndexParser,
-				   string ServerSha1,
 				   vector<DiffInfo> diffs)
    : pkgAcqBaseIndex(Owner, Target, ExpectedHashes, MetaIndexParser),
-     available_patches(diffs), ServerSha1(ServerSha1)
+     available_patches(diffs)
 {
-   
    DestFile = _config->FindDir("Dir::State::lists") + "partial/";
    DestFile += URItoFileName(Target->URI);
 
@@ -703,15 +814,21 @@ bool pkgAcqIndexDiffs::QueueNextDiff()					/*{{{*/
    FinalFile += URItoFileName(RealURI);
 
    FileFd fd(FinalFile, FileFd::ReadOnly);
-   SHA1Summation SHA1;
-   SHA1.AddFD(fd);
-   string local_sha1 = string(SHA1.Result());
+   Hashes LocalHashesCalc;
+   LocalHashesCalc.AddFD(fd);
+   HashStringList const LocalHashes = LocalHashesCalc.GetHashStringList();
+
    if(Debug)
-      std::clog << "QueueNextDiff: " 
-		<< FinalFile << " (" << local_sha1 << ")"<<std::endl;
+      std::clog << "QueueNextDiff: " << FinalFile << " (" << LocalHashes.find(NULL)->toStr() << ")" << std::endl;
+
+   if (unlikely(LocalHashes.usable() == false || ExpectedHashes.usable() == false))
+   {
+      Failed("Local/Expected hashes are not usable", NULL);
+      return false;
+   }
 
    // final file reached before all patches are applied
-   if(local_sha1 == ServerSha1)
+   if(LocalHashes == ExpectedHashes)
    {
       Finish(true);
       return true;
@@ -719,10 +836,10 @@ bool pkgAcqIndexDiffs::QueueNextDiff()					/*{{{*/
 
    // remove all patches until the next matching patch is found
    // this requires the Index file to be ordered
-   for(vector<DiffInfo>::iterator I=available_patches.begin();
+   for(vector<DiffInfo>::iterator I = available_patches.begin();
        available_patches.empty() == false &&
 	  I != available_patches.end() &&
-	  I->sha1 != local_sha1;
+	  I->result_hashes != LocalHashes;
        ++I)
    {
       available_patches.erase(I);
@@ -731,7 +848,7 @@ bool pkgAcqIndexDiffs::QueueNextDiff()					/*{{{*/
    // error checking and falling back if no patch was found
    if(available_patches.empty() == true)
    {
-      Failed("", NULL);
+      Failed("No patches left to reach target", NULL);
       return false;
    }
 
@@ -743,7 +860,7 @@ bool pkgAcqIndexDiffs::QueueNextDiff()					/*{{{*/
 
    if(Debug)
       std::clog << "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc.URI << std::endl;
-   
+
    QueueURI(Desc);
 
    return true;
@@ -763,6 +880,17 @@ void pkgAcqIndexDiffs::Done(string Message,unsigned long long Size, HashStringLi
    // success in downloading a diff, enter ApplyDiff state
    if(State == StateFetchDiff)
    {
+      FileFd fd(DestFile, FileFd::ReadOnly, FileFd::Gzip);
+      class Hashes LocalHashesCalc;
+      LocalHashesCalc.AddFD(fd);
+      HashStringList const LocalHashes = LocalHashesCalc.GetHashStringList();
+
+      if (fd.Size() != available_patches[0].patch_size ||
+	    available_patches[0].patch_hashes != LocalHashes)
+      {
+	 Failed("Patch has Size/Hashsum mismatch", NULL);
+	 return;
+      }
 
       // rred excepts the patch as $FinalFile.ed
       Rename(DestFile,FinalFile+".ed");
@@ -774,7 +902,15 @@ void pkgAcqIndexDiffs::Done(string Message,unsigned long long Size, HashStringLi
       Local = true;
       Desc.URI = "rred:" + FinalFile;
       QueueURI(Desc);
+      ActiveSubprocess = "rred";
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic push
+	#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
       Mode = "rred";
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic pop
+#endif
       return;
    } 
 
@@ -799,7 +935,7 @@ void pkgAcqIndexDiffs::Done(string Message,unsigned long long Size, HashStringLi
       if(available_patches.empty() == false) {
 	 new pkgAcqIndexDiffs(Owner, Target,
 			      ExpectedHashes, MetaIndexParser,
-                              ServerSha1, available_patches);
+			      available_patches);
 	 return Finish();
       } else 
 	 return Finish(true);
@@ -871,6 +1007,17 @@ void pkgAcqIndexMergeDiffs::Done(string Message,unsigned long long Size,HashStri
 
    if (State == StateFetchDiff)
    {
+      FileFd fd(DestFile, FileFd::ReadOnly, FileFd::Gzip);
+      class Hashes LocalHashesCalc;
+      LocalHashesCalc.AddFD(fd);
+      HashStringList const LocalHashes = LocalHashesCalc.GetHashStringList();
+
+      if (fd.Size() != patch.patch_size || patch.patch_hashes != LocalHashes)
+      {
+	 Failed("Patch has Size/Hashsum mismatch", NULL);
+	 return;
+      }
+
       // rred expects the patch as $FinalFile.ed.$patchname.gz
       Rename(DestFile, FinalFile + ".ed." + patch.file + ".gz");
 
@@ -894,7 +1041,15 @@ void pkgAcqIndexMergeDiffs::Done(string Message,unsigned long long Size,HashStri
       Local = true;
       Desc.URI = "rred:" + FinalFile;
       QueueURI(Desc);
+      ActiveSubprocess = "rred";
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic push
+	#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
       Mode = "rred";
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic pop
+#endif
       return;
    }
    // success in download/apply all diffs, clean up
@@ -952,8 +1107,6 @@ pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner,
    }
    CompressionExtension = comprExt;
 
-   Verify = true;
-
    Init(URI, URIDesc, ShortDesc);
 }
 pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner, IndexTarget const *Target,
@@ -979,13 +1132,6 @@ pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner, IndexTarget const *Target,
    if (CompressionExtension.empty() == false)
       CompressionExtension.erase(CompressionExtension.end()-1);
 
-   // only verify non-optional targets, see acquire-item.h for a FIXME
-   // to make this more flexible
-   if (Target->IsOptional())
-     Verify = false;
-   else
-     Verify = true;
-
    Init(Target->URI, Target->Description, Target->ShortDesc);
 }
 									/*}}}*/
@@ -1008,6 +1154,7 @@ void pkgAcqIndex::Init(string const &URI, string const &URIDesc, string const &S
    else
    {
       Desc.URI = URI + '.' + comprExt;
+      DestFile = DestFile + '.' + comprExt;
       if(Target)
          MetaKey = string(Target->MetaKey) + '.' + comprExt;
    }
@@ -1018,6 +1165,8 @@ void pkgAcqIndex::Init(string const &URI, string const &URIDesc, string const &S
       indexRecords::checkSum *Record = MetaIndexParser->Lookup(MetaKey);
       if(Record)
          FileSize = Record->Size;
+      
+      InitByHashIfNeeded(MetaKey);
    }
 
    Desc.Description = URIDesc;
@@ -1027,21 +1176,51 @@ void pkgAcqIndex::Init(string const &URI, string const &URIDesc, string const &S
    QueueURI(Desc);
 }
 									/*}}}*/
+// AcqIndex::AdjustForByHash - modify URI for by-hash support		/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+void pkgAcqIndex::InitByHashIfNeeded(const std::string MetaKey)
+{
+   // TODO:
+   //  - (maybe?) add support for by-hash into the sources.list as flag
+   //  - make apt-ftparchive generate the hashes (and expire?)
+   std::string HostKnob = "APT::Acquire::" + ::URI(Desc.URI).Host + "::By-Hash";
+   if(_config->FindB("APT::Acquire::By-Hash", false) == true ||
+      _config->FindB(HostKnob, false) == true ||
+      MetaIndexParser->GetSupportsAcquireByHash())
+   {
+      indexRecords::checkSum *Record = MetaIndexParser->Lookup(MetaKey);
+      if(Record)
+      {
+         // FIXME: should we really use the best hash here? or a fixed one?
+         const HashString *TargetHash = Record->Hashes.find("");
+         std::string ByHash = "/by-hash/" + TargetHash->HashType() + "/" + TargetHash->HashValue();
+         size_t trailing_slash = Desc.URI.find_last_of("/");
+         Desc.URI = Desc.URI.replace(
+            trailing_slash,
+            Desc.URI.substr(trailing_slash+1).size()+1,
+            ByHash);
+      } else {
+         _error->Warning(
+            "Fetching ByHash requested but can not find record for %s",
+            MetaKey.c_str());
+      }
+   }
+}
+									/*}}}*/
 // AcqIndex::Custom600Headers - Insert custom request headers		/*{{{*/
 // ---------------------------------------------------------------------
 /* The only header we use is the last-modified header. */
 string pkgAcqIndex::Custom600Headers() const
 {
+   std::string const compExt = CompressionExtension.substr(0, CompressionExtension.find(' '));
    string Final = _config->FindDir("Dir::State::lists");
    Final += URItoFileName(RealURI);
    if (_config->FindB("Acquire::GzipIndexes",false))
-      Final += ".gz";
+      Final += compExt;
    
    string msg = "\nIndex-File: true";
-   // FIXME: this really should use "IndexTarget::IsOptional()" but that
-   //        seems to be difficult without breaking ABI
-   if (ShortDesc().find("Translation") != 0)
-      msg += "\nFail-Ignore: true";
+
    struct stat Buf;
    if (stat(Final.c_str(),&Buf) == 0)
       msg += "\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
@@ -1069,6 +1248,31 @@ void pkgAcqIndex::Failed(string Message,pkgAcquire::MethodConfig *Cnf)	/*{{{*/
    Item::Failed(Message,Cnf);
 }
 									/*}}}*/
+// pkgAcqIndex::GetFinalFilename - Return the full final file path      /*{{{*/
+std::string pkgAcqIndex::GetFinalFilename(std::string const &URI,
+                                          std::string const &compExt)
+{
+   std::string FinalFile = _config->FindDir("Dir::State::lists");
+   FinalFile += URItoFileName(URI);
+   if (_config->FindB("Acquire::GzipIndexes",false) == true)
+      FinalFile += '.' + compExt;
+   return FinalFile;
+}
+									/*}}}*/
+// AcqIndex::ReverifyAfterIMS - Reverify index after an ims-hit		/*{{{*/
+void pkgAcqIndex::ReverifyAfterIMS(std::string const &FileName)
+{
+   std::string const compExt = CompressionExtension.substr(0, CompressionExtension.find(' '));
+   if (_config->FindB("Acquire::GzipIndexes",false) == true)
+      DestFile += compExt;
+
+   string FinalFile = GetFinalFilename(RealURI, compExt);
+   Rename(FinalFile, FileName);
+   Decompression = true;
+   Desc.URI = "copy:" + FileName;
+   QueueURI(Desc);
+}
+									/*}}}*/
 // AcqIndex::Done - Finished a fetch					/*{{{*/
 // ---------------------------------------------------------------------
 /* This goes through a number of states.. On the initial fetch the
@@ -1080,39 +1284,41 @@ void pkgAcqIndex::Done(string Message,unsigned long long Size,HashStringList con
 		       pkgAcquire::MethodConfig *Cfg)
 {
    Item::Done(Message,Size,Hashes,Cfg);
+   std::string const compExt = CompressionExtension.substr(0, CompressionExtension.find(' '));
 
    if (Decompression == true)
    {
       if (ExpectedHashes.usable() && ExpectedHashes != Hashes)
       {
+         Desc.URI = RealURI;
 	 RenameOnError(HashSumMismatch);
 	 printHashSumComparision(RealURI, ExpectedHashes, Hashes);
          return;
       }
 
-      /* Verify the index file for correctness (all indexes must
-       * have a Package field) (LP: #346386) (Closes: #627642) */
-      if (Verify == true)
+      // FIXME: this can go away once we only ever download stuff that
+      //        has a valid hash and we never do GET based probing
+      //
+      /* Always verify the index file for correctness (all indexes must
+       * have a Package field) (LP: #346386) (Closes: #627642) 
+       */
+      FileFd fd(DestFile, FileFd::ReadOnly, FileFd::Extension);
+      // Only test for correctness if the file is not empty (empty is ok)
+      if (fd.Size() > 0)
       {
-	 FileFd fd(DestFile, FileFd::ReadOnly);
-	 // Only test for correctness if the file is not empty (empty is ok)
-	 if (fd.FileSize() > 0)
-	 {
-	    pkgTagSection sec;
-	    pkgTagFile tag(&fd);
-
-	    // all our current indexes have a field 'Package' in each section
-	    if (_error->PendingError() == true || tag.Step(sec) == false || sec.Exists("Package") == false)
-	    {
-	       RenameOnError(InvalidFormat);
-	       return;
-	    }
+         pkgTagSection sec;
+         pkgTagFile tag(&fd);
+         
+         // all our current indexes have a field 'Package' in each section
+         if (_error->PendingError() == true || tag.Step(sec) == false || sec.Exists("Package") == false)
+         {
+            RenameOnError(InvalidFormat);
+            return;
          }
       }
        
       // Done, move it into position
-      string FinalFile = _config->FindDir("Dir::State::lists");
-      FinalFile += URItoFileName(RealURI);
+      string FinalFile = GetFinalFilename(RealURI, compExt);
       Rename(DestFile,FinalFile);
       chmod(FinalFile.c_str(),0644);
 
@@ -1120,7 +1326,9 @@ void pkgAcqIndex::Done(string Message,unsigned long long Size,HashStringList con
          will work OK */
       DestFile = _config->FindDir("Dir::State::lists") + "partial/";
       DestFile += URItoFileName(RealURI);
-      
+      if (_config->FindB("Acquire::GzipIndexes",false))
+         DestFile += '.' + compExt;
+
       // Remove the compressed version.
       if (Erase == true)
 	 unlink(DestFile.c_str());
@@ -1135,15 +1343,20 @@ void pkgAcqIndex::Done(string Message,unsigned long long Size,HashStringList con
    string FileName = LookupTag(Message,"Alt-Filename");
    if (FileName.empty() == false)
    {
-      // The files timestamp matches
-      if (StringToBool(LookupTag(Message,"Alt-IMS-Hit"),false) == true)
-	 return;
       Decompression = true;
       Local = true;
       DestFile += ".decomp";
       Desc.URI = "copy:" + FileName;
       QueueURI(Desc);
+      ActiveSubprocess = "copy";
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic push
+	#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
       Mode = "copy";
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic pop
+#endif
       return;
    }
 
@@ -1154,33 +1367,44 @@ void pkgAcqIndex::Done(string Message,unsigned long long Size,HashStringList con
       ErrorText = "Method gave a blank filename";
    }
 
-   std::string const compExt = CompressionExtension.substr(0, CompressionExtension.find(' '));
-
-   // The files timestamp matches
-   if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true) {
-       if (_config->FindB("Acquire::GzipIndexes",false) && compExt == "gz")
-	  // Update DestFile for .gz suffix so that the clean operation keeps it
-	  DestFile += ".gz";
-      return;
-    }
-
    if (FileName == DestFile)
       Erase = true;
    else
       Local = true;
-   
+
+   // do not reverify cdrom sources as apt-cdrom may rewrite the Packages
+   // file when its doing the indexcopy
+   if (RealURI.substr(0,6) == "cdrom:" &&
+       StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
+      return;
+
+   // The files timestamp matches, for non-local URLs reverify the local
+   // file, for local file, uncompress again to ensure the hashsum is still
+   // matching the Release file
+   if (!Local && StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
+   {
+      // set destfile to the final destfile
+      if(_config->FindB("Acquire::GzipIndexes",false) == false)
+      {
+         DestFile = _config->FindDir("Dir::State::lists") + "partial/";
+         DestFile += URItoFileName(RealURI);
+      }
+
+      ReverifyAfterIMS(FileName);
+      return;
+   }
    string decompProg;
 
-   // If we enable compressed indexes and already have gzip, keep it
-   if (_config->FindB("Acquire::GzipIndexes",false) && compExt == "gz" && !Local) {
-      string FinalFile = _config->FindDir("Dir::State::lists");
-      FinalFile += URItoFileName(RealURI) + ".gz";
-      Rename(DestFile,FinalFile);
-      chmod(FinalFile.c_str(),0644);
-      
-      // Update DestFile for .gz suffix so that the clean operation keeps it
-      DestFile = _config->FindDir("Dir::State::lists") + "partial/";
-      DestFile += URItoFileName(RealURI) + ".gz";
+   // If we enable compressed indexes, queue for hash verification
+   if (_config->FindB("Acquire::GzipIndexes",false))
+   {
+      DestFile = _config->FindDir("Dir::State::lists");
+      DestFile += URItoFileName(RealURI) + '.' + compExt;
+
+      Decompression = true;
+      Desc.URI = "copy:" + FileName;
+      QueueURI(Desc);
+
       return;
     }
 
@@ -1199,8 +1423,15 @@ void pkgAcqIndex::Done(string Message,unsigned long long Size,HashStringList con
    Desc.URI = decompProg + ":" + FileName;
    QueueURI(Desc);
 
-   // FIXME: this points to a c++ string that goes out of scope
-   Mode = decompProg.c_str();
+   ActiveSubprocess = decompProg;
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic push
+	#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+      Mode = ActiveSubprocess.c_str();
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic pop
+#endif
 }
 									/*}}}*/
 // AcqIndexTrans::pkgAcqIndexTrans - Constructor			/*{{{*/
@@ -1225,8 +1456,11 @@ pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire *Owner, IndexTarget const * const
 // ---------------------------------------------------------------------
 string pkgAcqIndexTrans::Custom600Headers() const
 {
+   std::string const compExt = CompressionExtension.substr(0, CompressionExtension.find(' '));
    string Final = _config->FindDir("Dir::State::lists");
    Final += URItoFileName(RealURI);
+   if (_config->FindB("Acquire::GzipIndexes",false))
+      Final += compExt;
 
    struct stat Buf;
    if (stat(Final.c_str(),&Buf) != 0)
@@ -1499,7 +1733,15 @@ void pkgAcqMetaIndex::Done(string Message,unsigned long long Size,HashStringList
          AuthPass = true;
          Desc.URI = "gpgv:" + SigFile;
          QueueURI(Desc);
-         Mode = "gpgv";
+	 ActiveSubprocess = "gpgv";
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic push
+	#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+	 Mode = "gpgv";
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic pop
+#endif
 	 return;
       }
    }
@@ -1580,6 +1822,32 @@ void pkgAcqMetaIndex::AuthDone(string Message)				/*{{{*/
       std::cerr << "Signature verification succeeded: "
                 << DestFile << std::endl;
 
+   // do not trust any previously unverified content that we may have
+   string LastGoodSigFile = _config->FindDir("Dir::State::lists").append("partial/").append(URItoFileName(RealURI));
+   if (DestFile != SigFile)
+      LastGoodSigFile.append(".gpg");
+   LastGoodSigFile.append(".reverify");
+   if(IMSHit == false && RealFileExists(LastGoodSigFile) == false)
+   {
+      for (vector <struct IndexTarget*>::const_iterator Target = IndexTargets->begin();
+           Target != IndexTargets->end();
+           ++Target)
+      {
+         // remove old indexes
+         std::string index = _config->FindDir("Dir::State::lists") +
+            URItoFileName((*Target)->URI);
+         unlink(index.c_str());
+         // and also old gzipindexes
+         std::vector<std::string> types = APT::Configuration::getCompressionTypes();
+         for (std::vector<std::string>::const_iterator t = types.begin(); t != types.end(); ++t)
+         {
+            index += '.' + (*t);
+            unlink(index.c_str());
+         }
+      }
+   }
+
+
    // Download further indexes with verification
    QueueIndexes(true);
 

+ 47 - 36
apt-pkg/acquire-item.h

@@ -133,7 +133,12 @@ class pkgAcquire::Item : public WeakPointable
    /** \brief If not \b NULL, contains the name of a subprocess that
     *  is operating on this object (for instance, "gzip" or "gpgv").
     */
-   const char *Mode;
+   APT_DEPRECATED const char *Mode;
+
+   /** \brief contains the name of the subprocess that is operating on this object
+    * (for instance, "gzip", "rred" or "gpgv"). This is obsoleting #Mode from above
+    * as it can manage the lifetime of included string properly. */
+   std::string ActiveSubprocess;
 
    /** \brief A client-supplied unique identifier.
     * 
@@ -245,12 +250,12 @@ class pkgAcquire::Item : public WeakPointable
     *
     *  \return a URI that should be used to describe what is being fetched.
     */
-   virtual std::string DescURI() const = 0;
+   virtual std::string DescURI() = 0;
    /** \brief Short item description.
     *
     *  \return a brief description of the object being fetched.
     */
-   virtual std::string ShortDesc() const {return DescURI();}
+   virtual std::string ShortDesc() {return DescURI();}
 
    /** \brief Invoked by the worker when the download is completely done. */
    virtual void Finished() {};
@@ -289,7 +294,8 @@ class pkgAcquire::Item : public WeakPointable
     *  \param Owner The new owner of this item.
     *  \param ExpectedHashes of the file represented by this item
     */
-   Item(pkgAcquire *Owner, HashStringList const &ExpectedHashes);
+   Item(pkgAcquire *Owner,
+        HashStringList const &ExpectedHashes=HashStringList());
 
    /** \brief Remove this item from its owner's queue by invoking
     *  pkgAcquire::Remove.
@@ -322,11 +328,17 @@ struct DiffInfo {
    /** The filename of the diff. */
    std::string file;
 
-   /** The sha1 hash of the diff. */
-   std::string sha1;
+   /** The hashes of the diff */
+   HashStringList result_hashes;
+
+   /** The hashes of the file after the diff is applied */
+   HashStringList patch_hashes;
+
+   /** The size of the file after the diff is applied */
+   unsigned long long result_size;
 
-   /** The size of the diff. */
-   unsigned long size;
+   /** The size of the diff itself */
+   unsigned long long patch_size;
 };
 									/*}}}*/
 /** \brief An item that is responsible for fetching a SubIndex		{{{
@@ -346,7 +358,7 @@ class pkgAcqSubIndex : public pkgAcquire::Item
    virtual void Failed(std::string Message,pkgAcquire::MethodConfig *Cnf);
    virtual void Done(std::string Message,unsigned long long Size, HashStringList const &Hashes,
 		     pkgAcquire::MethodConfig *Cnf);
-   virtual std::string DescURI() const {return Desc.URI;};
+   virtual std::string DescURI() {return Desc.URI;};
    virtual std::string Custom600Headers() const;
    virtual bool ParseIndex(std::string const &IndexFile);
 
@@ -422,7 +434,7 @@ class pkgAcqDiffIndex : public pkgAcqBaseIndex
    virtual void Failed(std::string Message,pkgAcquire::MethodConfig *Cnf);
    virtual void Done(std::string Message,unsigned long long Size, HashStringList const &Hashes,
 		     pkgAcquire::MethodConfig *Cnf);
-   virtual std::string DescURI() const {return RealURI + "Index";};
+   virtual std::string DescURI() {return RealURI + "Index";};
    virtual std::string Custom600Headers() const;
 
    /** \brief Parse the Index file for a set of Packages diffs.
@@ -515,7 +527,7 @@ class pkgAcqIndexMergeDiffs : public pkgAcqBaseIndex
    virtual void Failed(std::string Message,pkgAcquire::MethodConfig *Cnf);
    virtual void Done(std::string Message,unsigned long long Size, HashStringList const &Hashes,
 	 pkgAcquire::MethodConfig *Cnf);
-   virtual std::string DescURI() const {return RealURI + "Index";};
+   virtual std::string DescURI() {return RealURI + "Index";};
 
    /** \brief Create an index merge-diff item.
     *
@@ -570,7 +582,7 @@ class pkgAcqIndexDiffs : public pkgAcqBaseIndex
     *  \return \b true if an applicable diff was found, \b false
     *  otherwise.
     */
-   bool QueueNextDiff();
+   APT_HIDDEN bool QueueNextDiff();
 
    /** \brief Handle tasks that must be performed after the item
     *  finishes downloading.
@@ -583,7 +595,7 @@ class pkgAcqIndexDiffs : public pkgAcqBaseIndex
     *  \param allDone If \b true, the file was entirely reconstructed,
     *  and its md5sum is verified. 
     */
-   void Finish(bool allDone=false);
+   APT_HIDDEN void Finish(bool allDone=false);
 
    protected:
 
@@ -610,9 +622,6 @@ class pkgAcqIndexDiffs : public pkgAcqBaseIndex
     */
    std::vector<DiffInfo> available_patches;
 
-   /** Stop applying patches when reaching that sha1 */
-   std::string ServerSha1;
-
    /** The current status of this patch. */
    enum DiffState
      {
@@ -640,7 +649,7 @@ class pkgAcqIndexDiffs : public pkgAcqBaseIndex
 
    virtual void Done(std::string Message,unsigned long long Size, HashStringList const &Hashes,
 		     pkgAcquire::MethodConfig *Cnf);
-   virtual std::string DescURI() const {return RealURI + "Index";};
+   virtual std::string DescURI() {return RealURI + "Index";};
 
    /** \brief Create an index diff item.
     *
@@ -656,12 +665,10 @@ class pkgAcqIndexDiffs : public pkgAcqBaseIndex
     *
     *  \param ShortDesc A brief description of this item.
     *
-    *  \param ExpectedHashes The expected md5sum of the completely
+    *  \param ExpectedHashes The expected hashsums of the completely
     *  reconstructed package index file; the index file will be tested
     *  against this value when it is entirely reconstructed.
     *
-    *  \param ServerSha1 is the sha1sum of the current file on the server
-    *
     *  \param diffs The remaining diffs from the index of diffs.  They
     *  should be ordered so that each diff appears before any diff
     *  that depends on it.
@@ -670,7 +677,6 @@ class pkgAcqIndexDiffs : public pkgAcqBaseIndex
                     struct IndexTarget const * const Target,
                     HashStringList const &ExpectedHash,
                     indexRecords *MetaIndexParser,
-		    std::string ServerSha1,
 		    std::vector<DiffInfo> diffs=std::vector<DiffInfo>());
 };
 									/*}}}*/
@@ -693,15 +699,8 @@ class pkgAcqIndex : public pkgAcqBaseIndex
     */
    bool Erase;
 
-   /** \brief Verify for correctness by checking if a "Package"
-    *         tag is found in the index. This can be set to
-    *         false for optional index targets
-    *       
-    */
-   // FIXME: instead of a bool it should use a verify string that will
-   //        then be used in the pkgAcqIndex::Done method to ensure that
-   //        the downloaded file contains the expected tag
-   bool Verify;
+   // Unused, used to be used to verify that "Packages: " header was there
+   bool __DELME_ON_NEXT_ABI_BREAK_Verify;
 
    /** \brief The object that is actually being fetched (minus any
     *  compression-related extensions).
@@ -713,6 +712,18 @@ class pkgAcqIndex : public pkgAcqBaseIndex
     */
    std::string CompressionExtension;
 
+
+   /** \brief Do the changes needed to fetch via AptByHash (if needed) */
+   void InitByHashIfNeeded(const std::string MetaKey);
+
+   /** \brief Get the full pathname of the final file for the given URI
+    */
+   std::string GetFinalFilename(std::string const &URI,
+                                std::string const &compExt);
+
+   /** \brief Schedule file for verification after a IMS hit */
+   void ReverifyAfterIMS(std::string const &FileName);
+
    public:
    
    // Specialized action members
@@ -720,7 +731,7 @@ class pkgAcqIndex : public pkgAcqBaseIndex
    virtual void Done(std::string Message,unsigned long long Size, HashStringList const &Hashes,
 		     pkgAcquire::MethodConfig *Cnf);
    virtual std::string Custom600Headers() const;
-   virtual std::string DescURI() const {return Desc.URI;};
+   virtual std::string DescURI() {return Desc.URI;};
 
    /** \brief Create a pkgAcqIndex.
     *
@@ -884,7 +895,7 @@ class pkgAcqMetaSig : public pkgAcquire::Item
    virtual void Done(std::string Message,unsigned long long Size, HashStringList const &Hashes,
 		     pkgAcquire::MethodConfig *Cnf);
    virtual std::string Custom600Headers() const;
-   virtual std::string DescURI() const {return RealURI; };
+   virtual std::string DescURI() {return RealURI; };
 
    /** \brief Create a new pkgAcqMetaSig. */
    pkgAcqMetaSig(pkgAcquire *Owner,std::string URI,std::string URIDesc, std::string ShortDesc,
@@ -977,7 +988,7 @@ class pkgAcqMetaIndex : public pkgAcquire::Item
    virtual void Done(std::string Message,unsigned long long Size, HashStringList const &Hashes,
 		     pkgAcquire::MethodConfig *Cnf);
    virtual std::string Custom600Headers() const;
-   virtual std::string DescURI() const {return RealURI; };
+   virtual std::string DescURI() {return RealURI; };
 
    /** \brief Create a new pkgAcqMetaIndex. */
    pkgAcqMetaIndex(pkgAcquire *Owner,
@@ -1071,8 +1082,8 @@ class pkgAcqArchive : public pkgAcquire::Item
    virtual void Failed(std::string Message,pkgAcquire::MethodConfig *Cnf);
    virtual void Done(std::string Message,unsigned long long Size, HashStringList const &Hashes,
 		     pkgAcquire::MethodConfig *Cnf);
-   virtual std::string DescURI() const {return Desc.URI;};
-   virtual std::string ShortDesc() const {return Desc.ShortDesc;};
+   virtual std::string DescURI() {return Desc.URI;};
+   virtual std::string ShortDesc() {return Desc.ShortDesc;};
    virtual void Finished();
    virtual bool IsTrusted() const;
    
@@ -1121,7 +1132,7 @@ class pkgAcqFile : public pkgAcquire::Item
    virtual void Failed(std::string Message,pkgAcquire::MethodConfig *Cnf);
    virtual void Done(std::string Message,unsigned long long Size, HashStringList const &CalcHashes,
 		     pkgAcquire::MethodConfig *Cnf);
-   virtual std::string DescURI() const {return Desc.URI;};
+   virtual std::string DescURI() {return Desc.URI;};
    virtual std::string Custom600Headers() const;
 
    /** \brief Create a new pkgAcqFile object.

+ 12 - 0
apt-pkg/acquire-method.cc

@@ -118,6 +118,18 @@ void pkgAcqMethod::Fail(string Err,bool Transient)
 
    std::cout << "\n" << std::flush;
 }
+									/*}}}*/
+// AcqMethod::DropPrivsOrDie - Drop privileges or die		/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+void pkgAcqMethod::DropPrivsOrDie()
+{
+   if (!DropPrivs()) {
+      Fail(false);
+      exit(112);	/* call the european emergency number */
+   }
+}
+
 									/*}}}*/
 // AcqMethod::URIStart - Indicate a download is starting		/*{{{*/
 // ---------------------------------------------------------------------

+ 1 - 1
apt-pkg/acquire-method.h

@@ -106,7 +106,7 @@ class pkgAcqMethod
    
    pkgAcqMethod(const char *Ver,unsigned long Flags = 0);
    virtual ~pkgAcqMethod() {};
-
+   void DropPrivsOrDie();
    private:
    APT_HIDDEN void Dequeue();
 };

+ 26 - 28
apt-pkg/acquire.cc

@@ -73,23 +73,27 @@ pkgAcquire::pkgAcquire(pkgAcquireStatus *Progress) :  LockFD(-1), Queues(0), Wor
 // ---------------------------------------------------------------------
 /* Do everything needed to be a complete Acquire object and report the
    success (or failure) back so the user knows that something is wrong… */
-bool pkgAcquire::Setup(pkgAcquireStatus *Progress, string const &Lock)
+bool pkgAcquire::Setup(pkgAcquireStatus *Progress, string const &Lock,
+      bool const createDirectories)
 {
    Log = Progress;
 
    // check for existence and possibly create auxiliary directories
-   string const listDir = _config->FindDir("Dir::State::lists");
-   string const partialListDir = listDir + "partial/";
-   string const archivesDir = _config->FindDir("Dir::Cache::Archives");
-   string const partialArchivesDir = archivesDir + "partial/";
-
-   if (CreateAPTDirectoryIfNeeded(_config->FindDir("Dir::State"), partialListDir) == false &&
-       CreateAPTDirectoryIfNeeded(listDir, partialListDir) == false)
-      return _error->Errno("Acquire", _("List directory %spartial is missing."), listDir.c_str());
-
-   if (CreateAPTDirectoryIfNeeded(_config->FindDir("Dir::Cache"), partialArchivesDir) == false &&
-       CreateAPTDirectoryIfNeeded(archivesDir, partialArchivesDir) == false)
-      return _error->Errno("Acquire", _("Archives directory %spartial is missing."), archivesDir.c_str());
+   if (createDirectories == true)
+   {
+      string const listDir = _config->FindDir("Dir::State::lists");
+      string const partialListDir = listDir + "partial/";
+      string const archivesDir = _config->FindDir("Dir::Cache::Archives");
+      string const partialArchivesDir = archivesDir + "partial/";
+
+      if (CreateAPTDirectoryIfNeeded(_config->FindDir("Dir::State"), partialListDir) == false &&
+	    CreateAPTDirectoryIfNeeded(listDir, partialListDir) == false)
+	 return _error->Errno("Acquire", _("List directory %spartial is missing."), listDir.c_str());
+
+      if (CreateAPTDirectoryIfNeeded(_config->FindDir("Dir::Cache"), partialArchivesDir) == false &&
+	    CreateAPTDirectoryIfNeeded(archivesDir, partialArchivesDir) == false)
+	 return _error->Errno("Acquire", _("Archives directory %spartial is missing."), archivesDir.c_str());
+   }
 
    if (Lock.empty() == true || _config->FindB("Debug::NoLocking", false) == true)
       return true;
@@ -487,6 +491,9 @@ bool pkgAcquire::Clean(string Dir)
    if (DirectoryExists(Dir) == false)
       return true;
 
+   if(Dir == "/")
+      return _error->Error(_("Clean of %s is not supported"), Dir.c_str());
+
    DIR *D = opendir(Dir.c_str());   
    if (D == 0)
       return _error->Errno("opendir",_("Unable to read %s"),Dir.c_str());
@@ -578,27 +585,18 @@ pkgAcquire::UriIterator pkgAcquire::UriEnd()
 // Acquire::MethodConfig::MethodConfig - Constructor			/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-pkgAcquire::MethodConfig::MethodConfig()
+pkgAcquire::MethodConfig::MethodConfig() : d(NULL), Next(0), SingleInstance(false),
+   Pipeline(false), SendConfig(false), LocalOnly(false), NeedsCleanup(false),
+   Removable(false)
 {
-   SingleInstance = false;
-   Pipeline = false;
-   SendConfig = false;
-   LocalOnly = false;
-   Removable = false;
-   Next = 0;
 }
 									/*}}}*/
 // Queue::Queue - Constructor						/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-pkgAcquire::Queue::Queue(string Name,pkgAcquire *Owner) : Name(Name), 
-            Owner(Owner)
+pkgAcquire::Queue::Queue(string Name,pkgAcquire *Owner) : d(NULL), Next(0),
+   Name(Name), Items(0), Workers(0), Owner(Owner), PipeDepth(0), MaxPipeDepth(1)
 {
-   Items = 0;
-   Next = 0;
-   Workers = 0;
-   MaxPipeDepth = 1;
-   PipeDepth = 0;
 }
 									/*}}}*/
 // Queue::~Queue - Destructor						/*{{{*/
@@ -802,7 +800,7 @@ void pkgAcquire::Queue::Bump()
 // AcquireStatus::pkgAcquireStatus - Constructor			/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-pkgAcquireStatus::pkgAcquireStatus() : d(NULL), Update(true), MorePulses(false)
+pkgAcquireStatus::pkgAcquireStatus() : d(NULL), Percent(0), Update(true), MorePulses(false)
 {
    Start();
 }

+ 5 - 2
apt-pkg/acquire.h

@@ -352,8 +352,11 @@ class pkgAcquire
     *  \param Lock defines a lock file that should be acquired to ensure
     *  only one Acquire class is in action at the time or an empty string
     *  if no lock file should be used.
+    *  \param createDirectories can be used to disable the creation of directories,
+    *  e.g. if the fetcher is used with different directories later on
     */
-   bool Setup(pkgAcquireStatus *Progress = NULL, std::string const &Lock = "");
+   bool Setup(pkgAcquireStatus *Progress = NULL, std::string const &Lock = "",
+      bool const createDirectories = true);
 
    void SetLog(pkgAcquireStatus *Progress) { Log = Progress; }
 
@@ -585,7 +588,7 @@ class pkgAcquire::UriIterator
     *
     *  \param Q The queue over which this UriIterator should iterate.
     */
-   UriIterator(pkgAcquire::Queue *Q) : CurQ(Q), CurItem(0)
+   UriIterator(pkgAcquire::Queue *Q) : d(NULL), CurQ(Q), CurItem(0)
    {
       while (CurItem == 0 && CurQ != 0)
       {

+ 6 - 10
apt-pkg/algorithms.cc

@@ -640,13 +640,11 @@ bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg)
 // ProblemResolver::Resolve - calls a resolver to fix the situation	/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-bool pkgProblemResolver::Resolve(bool BrokenFix)
+bool pkgProblemResolver::Resolve(bool BrokenFix, OpProgress * const Progress)
 {
    std::string const solver = _config->Find("APT::Solver", "internal");
-   if (solver != "internal") {
-      OpTextProgress Prog(*_config);
-      return EDSP::ResolveExternal(solver.c_str(), Cache, false, false, false, &Prog);
-   }
+   if (solver != "internal")
+      return EDSP::ResolveExternal(solver.c_str(), Cache, false, false, false, Progress);
    return ResolveInternal(BrokenFix);
 }
 									/*}}}*/
@@ -1140,13 +1138,11 @@ bool pkgProblemResolver::InstOrNewPolicyBroken(pkgCache::PkgIterator I)
 /* This is the work horse of the soft upgrade routine. It is very gental 
    in that it does not install or remove any packages. It is assumed that the
    system was non-broken previously. */
-bool pkgProblemResolver::ResolveByKeep()
+bool pkgProblemResolver::ResolveByKeep(OpProgress * const Progress)
 {
    std::string const solver = _config->Find("APT::Solver", "internal");
-   if (solver != "internal") {
-      OpTextProgress Prog(*_config);
-      return EDSP::ResolveExternal(solver.c_str(), Cache, true, false, false, &Prog);
-   }
+   if (solver != "internal")
+      return EDSP::ResolveExternal(solver.c_str(), Cache, true, false, false, Progress);
    return ResolveByKeepInternal();
 }
 									/*}}}*/

+ 14 - 14
apt-pkg/algorithms.h

@@ -82,9 +82,9 @@ class pkgSimulate : public pkgPackageManager				/*{{{*/
    virtual bool Remove(PkgIterator Pkg,bool Purge);
 
 private:
-   void ShortBreaks();
-   void Describe(PkgIterator iPkg,std::ostream &out,bool Current,bool Candidate);
-   
+   APT_HIDDEN void ShortBreaks();
+   APT_HIDDEN void Describe(PkgIterator iPkg,std::ostream &out,bool Current,bool Candidate);
+
    public:
 
    pkgSimulate(pkgDepCache *Cache);
@@ -114,7 +114,7 @@ class pkgProblemResolver						/*{{{*/
    
    // Sort stuff
    static pkgProblemResolver *This;
-   static int ScoreSort(const void *a,const void *b) APT_PURE;
+   APT_HIDDEN static int ScoreSort(const void *a,const void *b) APT_PURE;
 
    struct PackageKill
    {
@@ -122,12 +122,12 @@ class pkgProblemResolver						/*{{{*/
       DepIterator Dep;
    };
 
-   void MakeScores();
-   bool DoUpgrade(pkgCache::PkgIterator Pkg);
+   APT_HIDDEN void MakeScores();
+   APT_HIDDEN bool DoUpgrade(pkgCache::PkgIterator Pkg);
+
+   APT_HIDDEN bool ResolveInternal(bool const BrokenFix = false);
+   APT_HIDDEN bool ResolveByKeepInternal();
 
-   bool ResolveInternal(bool const BrokenFix = false);
-   bool ResolveByKeepInternal();
-   
    protected:
    bool InstOrNewPolicyBroken(pkgCache::PkgIterator Pkg);
 
@@ -136,12 +136,12 @@ class pkgProblemResolver						/*{{{*/
    inline void Protect(pkgCache::PkgIterator Pkg) {Flags[Pkg->ID] |= Protected; Cache.MarkProtected(Pkg);};
    inline void Remove(pkgCache::PkgIterator Pkg) {Flags[Pkg->ID] |= ToRemove;};
    inline void Clear(pkgCache::PkgIterator Pkg) {Flags[Pkg->ID] &= ~(Protected | ToRemove);};
-   
-   // Try to intelligently resolve problems by installing and removing packages   
-   bool Resolve(bool BrokenFix = false);
-   
+
+   // Try to intelligently resolve problems by installing and removing packages
+   bool Resolve(bool BrokenFix = false, OpProgress * const Progress = NULL);
+
    // Try to resolve problems only by using keep
-   bool ResolveByKeep();
+   bool ResolveByKeep(OpProgress * const Progress = NULL);
 
    APT_DEPRECATED void InstallProtect();
 

+ 29 - 29
apt-pkg/aptconfiguration.cc

@@ -32,6 +32,35 @@
 #include <apti18n.h>
 									/*}}}*/
 namespace APT {
+// setDefaultConfigurationForCompressors				/*{{{*/
+static void setDefaultConfigurationForCompressors() {
+	// Set default application paths to check for optional compression types
+	_config->CndSet("Dir::Bin::bzip2", "/bin/bzip2");
+	_config->CndSet("Dir::Bin::xz", "/usr/bin/xz");
+	if (FileExists(_config->FindFile("Dir::Bin::xz")) == true) {
+		_config->Set("Dir::Bin::lzma", _config->FindFile("Dir::Bin::xz"));
+		_config->Set("APT::Compressor::lzma::Binary", "xz");
+		if (_config->Exists("APT::Compressor::lzma::CompressArg") == false) {
+			_config->Set("APT::Compressor::lzma::CompressArg::", "--format=lzma");
+			_config->Set("APT::Compressor::lzma::CompressArg::", "-9");
+		}
+		if (_config->Exists("APT::Compressor::lzma::UncompressArg") == false) {
+			_config->Set("APT::Compressor::lzma::UncompressArg::", "--format=lzma");
+			_config->Set("APT::Compressor::lzma::UncompressArg::", "-d");
+		}
+	} else {
+		_config->CndSet("Dir::Bin::lzma", "/usr/bin/lzma");
+		if (_config->Exists("APT::Compressor::lzma::CompressArg") == false) {
+			_config->Set("APT::Compressor::lzma::CompressArg::", "--suffix=");
+			_config->Set("APT::Compressor::lzma::CompressArg::", "-9");
+		}
+		if (_config->Exists("APT::Compressor::lzma::UncompressArg") == false) {
+			_config->Set("APT::Compressor::lzma::UncompressArg::", "--suffix=");
+			_config->Set("APT::Compressor::lzma::UncompressArg::", "-d");
+		}
+	}
+}
+									/*}}}*/
 // getCompressionTypes - Return Vector of usable compressiontypes	/*{{{*/
 // ---------------------------------------------------------------------
 /* return a vector of compression types in the preferred order. */
@@ -402,35 +431,6 @@ bool Configuration::checkArchitecture(std::string const &Arch) {
 	return (std::find(archs.begin(), archs.end(), Arch) != archs.end());
 }
 									/*}}}*/
-// setDefaultConfigurationForCompressors				/*{{{*/
-void Configuration::setDefaultConfigurationForCompressors() {
-	// Set default application paths to check for optional compression types
-	_config->CndSet("Dir::Bin::bzip2", "/bin/bzip2");
-	_config->CndSet("Dir::Bin::xz", "/usr/bin/xz");
-	if (FileExists(_config->FindFile("Dir::Bin::xz")) == true) {
-		_config->Set("Dir::Bin::lzma", _config->FindFile("Dir::Bin::xz"));
-		_config->Set("APT::Compressor::lzma::Binary", "xz");
-		if (_config->Exists("APT::Compressor::lzma::CompressArg") == false) {
-			_config->Set("APT::Compressor::lzma::CompressArg::", "--format=lzma");
-			_config->Set("APT::Compressor::lzma::CompressArg::", "-9");
-		}
-		if (_config->Exists("APT::Compressor::lzma::UncompressArg") == false) {
-			_config->Set("APT::Compressor::lzma::UncompressArg::", "--format=lzma");
-			_config->Set("APT::Compressor::lzma::UncompressArg::", "-d");
-		}
-	} else {
-		_config->CndSet("Dir::Bin::lzma", "/usr/bin/lzma");
-		if (_config->Exists("APT::Compressor::lzma::CompressArg") == false) {
-			_config->Set("APT::Compressor::lzma::CompressArg::", "--suffix=");
-			_config->Set("APT::Compressor::lzma::CompressArg::", "-9");
-		}
-		if (_config->Exists("APT::Compressor::lzma::UncompressArg") == false) {
-			_config->Set("APT::Compressor::lzma::UncompressArg::", "--suffix=");
-			_config->Set("APT::Compressor::lzma::UncompressArg::", "-d");
-		}
-	}
-}
-									/*}}}*/
 // getCompressors - Return Vector of usealbe compressors		/*{{{*/
 // ---------------------------------------------------------------------
 /* return a vector of compressors used by apt-ftparchive in the

+ 0 - 3
apt-pkg/aptconfiguration.h

@@ -123,9 +123,6 @@ public:									/*{{{*/
 	/** \return Return a comma-separated list of enabled build profile specifications */
 	std::string static const getBuildProfilesString();
 									/*}}}*/
-	private:							/*{{{*/
-	void static setDefaultConfigurationForCompressors();
-									/*}}}*/
 };
 									/*}}}*/
 }

+ 3 - 0
apt-pkg/cachefile.cc

@@ -143,6 +143,9 @@ bool pkgCacheFile::BuildDepCache(OpProgress *Progress)
    if (DCache != NULL)
       return true;
 
+   if (BuildPolicy(Progress) == false)
+      return false;
+
    DCache = new pkgDepCache(Cache,Policy);
    if (_error->PendingError() == true)
       return false;

+ 119 - 25
apt-pkg/cachefilter.cc

@@ -6,6 +6,7 @@
 // Include Files							/*{{{*/
 #include <config.h>
 
+#include <apt-pkg/cachefile.h>
 #include <apt-pkg/cachefilter.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/pkgcache.h>
@@ -22,7 +23,11 @@
 									/*}}}*/
 namespace APT {
 namespace CacheFilter {
-PackageNameMatchesRegEx::PackageNameMatchesRegEx(std::string const &Pattern) : d(NULL) {/*{{{*/
+APT_CONST Matcher::~Matcher() {}
+APT_CONST PackageMatcher::~PackageMatcher() {}
+
+// Name matches RegEx							/*{{{*/
+PackageNameMatchesRegEx::PackageNameMatchesRegEx(std::string const &Pattern) {
 	pattern = new regex_t;
 	int const Res = regcomp(pattern, Pattern.c_str(), REG_EXTENDED | REG_ICASE | REG_NOSUB);
 	if (Res == 0)
@@ -34,41 +39,36 @@ PackageNameMatchesRegEx::PackageNameMatchesRegEx(std::string const &Pattern) : d
 	regerror(Res, pattern, Error, sizeof(Error));
 	_error->Error(_("Regex compilation error - %s"), Error);
 }
-									/*}}}*/
-bool PackageNameMatchesRegEx::operator() (pkgCache::PkgIterator const &Pkg) {/*{{{*/
+bool PackageNameMatchesRegEx::operator() (pkgCache::PkgIterator const &Pkg) {
 	if (unlikely(pattern == NULL))
 		return false;
 	else
 		return regexec(pattern, Pkg.Name(), 0, 0, 0) == 0;
 }
-									/*}}}*/
-bool PackageNameMatchesRegEx::operator() (pkgCache::GrpIterator const &Grp) {/*{{{*/
+bool PackageNameMatchesRegEx::operator() (pkgCache::GrpIterator const &Grp) {
 	if (unlikely(pattern == NULL))
 		return false;
 	else
 		return regexec(pattern, Grp.Name(), 0, 0, 0) == 0;
 }
-									/*}}}*/
-PackageNameMatchesRegEx::~PackageNameMatchesRegEx() {			/*{{{*/
+PackageNameMatchesRegEx::~PackageNameMatchesRegEx() {
 	if (pattern == NULL)
 		return;
 	regfree(pattern);
 	delete pattern;
 }
 									/*}}}*/
-
-// Fnmatch support					/*{{{*/
-//----------------------------------------------------------------------
-bool PackageNameMatchesFnmatch::operator() (pkgCache::PkgIterator const &Pkg) {/*{{{*/
+// Name matches Fnmatch							/*{{{*/
+PackageNameMatchesFnmatch::PackageNameMatchesFnmatch(std::string const &Pattern) :
+   Pattern(Pattern) {}
+bool PackageNameMatchesFnmatch::operator() (pkgCache::PkgIterator const &Pkg) {
    return fnmatch(Pattern.c_str(), Pkg.Name(), FNM_CASEFOLD) == 0;
 }
-									/*}}}*/
-bool PackageNameMatchesFnmatch::operator() (pkgCache::GrpIterator const &Grp) {/*{{{*/
+bool PackageNameMatchesFnmatch::operator() (pkgCache::GrpIterator const &Grp) {
    return fnmatch(Pattern.c_str(), Grp.Name(), FNM_CASEFOLD) == 0;
 }
 									/*}}}*/
-
-// CompleteArch to <kernel>-<cpu> tuple					/*{{{*/
+// Architecture matches <kernel>-<cpu> specification			/*{{{*/
 //----------------------------------------------------------------------
 /* The complete architecture, consisting of <kernel>-<cpu>. */
 static std::string CompleteArch(std::string const &arch) {
@@ -82,12 +82,10 @@ static std::string CompleteArch(std::string const &arch) {
 	else if (arch == "any")			return "*-*";
 	else					return "linux-" + arch;
 }
-									/*}}}*/
-PackageArchitectureMatchesSpecification::PackageArchitectureMatchesSpecification(std::string const &pattern, bool const isPattern) :/*{{{*/
-					literal(pattern), complete(CompleteArch(pattern)), isPattern(isPattern), d(NULL) {
+PackageArchitectureMatchesSpecification::PackageArchitectureMatchesSpecification(std::string const &pattern, bool const isPattern) :
+					literal(pattern), complete(CompleteArch(pattern)), isPattern(isPattern) {
 }
-									/*}}}*/
-bool PackageArchitectureMatchesSpecification::operator() (char const * const &arch) {/*{{{*/
+bool PackageArchitectureMatchesSpecification::operator() (char const * const &arch) {
 	if (strcmp(literal.c_str(), arch) == 0 ||
 	    strcmp(complete.c_str(), arch) == 0)
 		return true;
@@ -96,16 +94,112 @@ bool PackageArchitectureMatchesSpecification::operator() (char const * const &ar
 		return fnmatch(complete.c_str(), pkgarch.c_str(), 0) == 0;
 	return fnmatch(pkgarch.c_str(), complete.c_str(), 0) == 0;
 }
-									/*}}}*/
-bool PackageArchitectureMatchesSpecification::operator() (pkgCache::PkgIterator const &Pkg) {/*{{{*/
+bool PackageArchitectureMatchesSpecification::operator() (pkgCache::PkgIterator const &Pkg) {
 	return (*this)(Pkg.Arch());
+}
+PackageArchitectureMatchesSpecification::~PackageArchitectureMatchesSpecification() {
 }
 									/*}}}*/
-bool PackageArchitectureMatchesSpecification::operator() (pkgCache::VerIterator const &Ver) {/*{{{*/
-	return (*this)(Ver.ParentPkg());
+// Package is new install						/*{{{*/
+PackageIsNewInstall::PackageIsNewInstall(pkgCacheFile * const Cache) : Cache(Cache) {}
+APT_PURE bool PackageIsNewInstall::operator() (pkgCache::PkgIterator const &Pkg) {
+   return (*Cache)[Pkg].NewInstall();
 }
+PackageIsNewInstall::~PackageIsNewInstall() {}
 									/*}}}*/
-PackageArchitectureMatchesSpecification::~PackageArchitectureMatchesSpecification() {	/*{{{*/
+// Generica like True, False, NOT, AND, OR				/*{{{*/
+APT_CONST bool TrueMatcher::operator() (pkgCache::PkgIterator const &) { return true; }
+APT_CONST bool TrueMatcher::operator() (pkgCache::GrpIterator const &) { return true; }
+APT_CONST bool TrueMatcher::operator() (pkgCache::VerIterator const &) { return true; }
+
+APT_CONST bool FalseMatcher::operator() (pkgCache::PkgIterator const &) { return false; }
+APT_CONST bool FalseMatcher::operator() (pkgCache::GrpIterator const &) { return false; }
+APT_CONST bool FalseMatcher::operator() (pkgCache::VerIterator const &) { return false; }
+
+NOTMatcher::NOTMatcher(Matcher * const matcher) : matcher(matcher) {}
+bool NOTMatcher::operator() (pkgCache::PkgIterator const &Pkg) { return ! (*matcher)(Pkg); }
+bool NOTMatcher::operator() (pkgCache::GrpIterator const &Grp) { return ! (*matcher)(Grp); }
+bool NOTMatcher::operator() (pkgCache::VerIterator const &Ver) { return ! (*matcher)(Ver); }
+NOTMatcher::~NOTMatcher() { delete matcher; }
+
+ANDMatcher::ANDMatcher() {}
+ANDMatcher::ANDMatcher(Matcher * const matcher1) {
+   AND(matcher1);
+}
+ANDMatcher::ANDMatcher(Matcher * const matcher1, Matcher * const matcher2) {
+   AND(matcher1).AND(matcher2);
+}
+ANDMatcher::ANDMatcher(Matcher * const matcher1, Matcher * const matcher2, Matcher * const matcher3) {
+   AND(matcher1).AND(matcher2).AND(matcher3);
+}
+ANDMatcher::ANDMatcher(Matcher * const matcher1, Matcher * const matcher2, Matcher * const matcher3, Matcher * const matcher4) {
+   AND(matcher1).AND(matcher2).AND(matcher3).AND(matcher4);
+}
+ANDMatcher::ANDMatcher(Matcher * const matcher1, Matcher * const matcher2, Matcher * const matcher3, Matcher * const matcher4, Matcher * const matcher5) {
+   AND(matcher1).AND(matcher2).AND(matcher3).AND(matcher4).AND(matcher5);
+}
+ANDMatcher& ANDMatcher::AND(Matcher * const matcher) { matchers.push_back(matcher); return *this; }
+bool ANDMatcher::operator() (pkgCache::PkgIterator const &Pkg) {
+   for (std::vector<Matcher *>::const_iterator M = matchers.begin(); M != matchers.end(); ++M)
+      if ((**M)(Pkg) == false)
+	 return false;
+   return true;
+}
+bool ANDMatcher::operator() (pkgCache::GrpIterator const &Grp) {
+   for (std::vector<Matcher *>::const_iterator M = matchers.begin(); M != matchers.end(); ++M)
+      if ((**M)(Grp) == false)
+	 return false;
+   return true;
+}
+bool ANDMatcher::operator() (pkgCache::VerIterator const &Ver) {
+   for (std::vector<Matcher *>::const_iterator M = matchers.begin(); M != matchers.end(); ++M)
+      if ((**M)(Ver) == false)
+	 return false;
+   return true;
+}
+ANDMatcher::~ANDMatcher() {
+   for (std::vector<Matcher *>::iterator M = matchers.begin(); M != matchers.end(); ++M)
+      delete *M;
+}
+
+ORMatcher::ORMatcher() {}
+ORMatcher::ORMatcher(Matcher * const matcher1) {
+   OR(matcher1);
+}
+ORMatcher::ORMatcher(Matcher * const matcher1, Matcher * const matcher2) {
+   OR(matcher1).OR(matcher2);
+}
+ORMatcher::ORMatcher(Matcher * const matcher1, Matcher * const matcher2, Matcher * const matcher3) {
+   OR(matcher1).OR(matcher2).OR(matcher3);
+}
+ORMatcher::ORMatcher(Matcher * const matcher1, Matcher * const matcher2, Matcher * const matcher3, Matcher * const matcher4) {
+   OR(matcher1).OR(matcher2).OR(matcher3).OR(matcher4);
+}
+ORMatcher::ORMatcher(Matcher * const matcher1, Matcher * const matcher2, Matcher * const matcher3, Matcher * const matcher4, Matcher * const matcher5) {
+   OR(matcher1).OR(matcher2).OR(matcher3).OR(matcher4).OR(matcher5);
+}
+ORMatcher& ORMatcher::OR(Matcher * const matcher) { matchers.push_back(matcher); return *this; }
+bool ORMatcher::operator() (pkgCache::PkgIterator const &Pkg) {
+   for (std::vector<Matcher *>::const_iterator M = matchers.begin(); M != matchers.end(); ++M)
+      if ((**M)(Pkg) == true)
+	 return true;
+   return false;
+}
+bool ORMatcher::operator() (pkgCache::GrpIterator const &Grp) {
+   for (std::vector<Matcher *>::const_iterator M = matchers.begin(); M != matchers.end(); ++M)
+      if ((**M)(Grp) == true)
+	 return true;
+   return false;
+}
+bool ORMatcher::operator() (pkgCache::VerIterator const &Ver) {
+   for (std::vector<Matcher *>::const_iterator M = matchers.begin(); M != matchers.end(); ++M)
+      if ((**M)(Ver) == true)
+	 return true;
+   return false;
+}
+ORMatcher::~ORMatcher() {
+   for (std::vector<Matcher *>::iterator M = matchers.begin(); M != matchers.end(); ++M)
+      delete *M;
 }
 									/*}}}*/
 

+ 90 - 27
apt-pkg/cachefilter.h

@@ -10,28 +10,90 @@
 #include <apt-pkg/cacheiterators.h>
 
 #include <string>
+#include <vector>
 
 #include <regex.h>
+
+class pkgCacheFile;
 									/*}}}*/
 namespace APT {
 namespace CacheFilter {
 
-class PackageMatcher {
- public:
-   virtual bool operator() (pkgCache::PkgIterator const &/*Pkg*/) { 
-      return false; };
-   virtual bool operator() (pkgCache::GrpIterator const &/*Grp*/) { 
-      return false; };
-   virtual bool operator() (pkgCache::VerIterator const &/*Ver*/) {
-      return false; };
-   
-   virtual ~PackageMatcher() {};
+class Matcher {
+public:
+   virtual bool operator() (pkgCache::PkgIterator const &/*Pkg*/) = 0;
+   virtual bool operator() (pkgCache::GrpIterator const &/*Grp*/) = 0;
+   virtual bool operator() (pkgCache::VerIterator const &/*Ver*/) = 0;
+   virtual ~Matcher();
 };
 
-// PackageNameMatchesRegEx						/*{{{*/
-class PackageNameMatchesRegEx : public PackageMatcher {
-         /** \brief dpointer placeholder (for later in case we need it) */
-         void *d;
+class PackageMatcher : public Matcher {
+public:
+   virtual bool operator() (pkgCache::PkgIterator const &Pkg) = 0;
+   virtual bool operator() (pkgCache::VerIterator const &Ver) { return (*this)(Ver.ParentPkg()); }
+   virtual bool operator() (pkgCache::GrpIterator const &/*Grp*/) { return false; }
+   virtual ~PackageMatcher();
+};
+
+// Generica like True, False, NOT, AND, OR				/*{{{*/
+class TrueMatcher : public Matcher {
+public:
+   virtual bool operator() (pkgCache::PkgIterator const &Pkg);
+   virtual bool operator() (pkgCache::GrpIterator const &Grp);
+   virtual bool operator() (pkgCache::VerIterator const &Ver);
+};
+
+class FalseMatcher : public Matcher {
+public:
+   virtual bool operator() (pkgCache::PkgIterator const &Pkg);
+   virtual bool operator() (pkgCache::GrpIterator const &Grp);
+   virtual bool operator() (pkgCache::VerIterator const &Ver);
+};
+
+class NOTMatcher : public Matcher {
+   Matcher * const matcher;
+public:
+   NOTMatcher(Matcher * const matcher);
+   virtual bool operator() (pkgCache::PkgIterator const &Pkg);
+   virtual bool operator() (pkgCache::GrpIterator const &Grp);
+   virtual bool operator() (pkgCache::VerIterator const &Ver);
+   virtual ~NOTMatcher();
+};
+
+class ANDMatcher : public Matcher {
+   std::vector<Matcher *> matchers;
+public:
+   // 5 ought to be enough for everybody… c++11 variadic templates would be nice
+   ANDMatcher();
+   ANDMatcher(Matcher * const matcher1);
+   ANDMatcher(Matcher * const matcher1, Matcher * const matcher2);
+   ANDMatcher(Matcher * const matcher1, Matcher * const matcher2, Matcher * const matcher3);
+   ANDMatcher(Matcher * const matcher1, Matcher * const matcher2, Matcher * const matcher3, Matcher * const matcher4);
+   ANDMatcher(Matcher * const matcher1, Matcher * const matcher2, Matcher * const matcher3, Matcher * const matcher4, Matcher * const matcher5);
+   ANDMatcher& AND(Matcher * const matcher);
+   virtual bool operator() (pkgCache::PkgIterator const &Pkg);
+   virtual bool operator() (pkgCache::GrpIterator const &Grp);
+   virtual bool operator() (pkgCache::VerIterator const &Ver);
+   virtual ~ANDMatcher();
+};
+class ORMatcher : public Matcher {
+   std::vector<Matcher *> matchers;
+public:
+   // 5 ought to be enough for everybody… c++11 variadic templates would be nice
+   ORMatcher();
+   ORMatcher(Matcher * const matcher1);
+   ORMatcher(Matcher * const matcher1, Matcher * const matcher2);
+   ORMatcher(Matcher * const matcher1, Matcher * const matcher2, Matcher * const matcher3);
+   ORMatcher(Matcher * const matcher1, Matcher * const matcher2, Matcher * const matcher3, Matcher * const matcher4);
+   ORMatcher(Matcher * const matcher1, Matcher * const matcher2, Matcher * const matcher3, Matcher * const matcher4, Matcher * const matcher5);
+   ORMatcher& OR(Matcher * const matcher);
+   virtual bool operator() (pkgCache::PkgIterator const &Pkg);
+   virtual bool operator() (pkgCache::GrpIterator const &Grp);
+   virtual bool operator() (pkgCache::VerIterator const &Ver);
+   virtual ~ORMatcher();
+};
+									/*}}}*/
+class PackageNameMatchesRegEx : public PackageMatcher {			/*{{{*/
 	regex_t* pattern;
 public:
 	PackageNameMatchesRegEx(std::string const &Pattern);
@@ -40,20 +102,16 @@ public:
 	virtual ~PackageNameMatchesRegEx();
 };
 									/*}}}*/
-// PackageNameMatchesFnmatch						/*{{{*/
-   class PackageNameMatchesFnmatch : public PackageMatcher{
-         /** \brief dpointer placeholder (for later in case we need it) */
-         void *d;
-         const std::string Pattern;
+class PackageNameMatchesFnmatch : public PackageMatcher {		/*{{{*/
+	const std::string Pattern;
 public:
-         PackageNameMatchesFnmatch(std::string const &Pattern) 
-            : Pattern(Pattern) {};
-        virtual bool operator() (pkgCache::PkgIterator const &Pkg);
+	PackageNameMatchesFnmatch(std::string const &Pattern);
+	virtual bool operator() (pkgCache::PkgIterator const &Pkg);
 	virtual bool operator() (pkgCache::GrpIterator const &Grp);
 	virtual ~PackageNameMatchesFnmatch() {};
 };
 									/*}}}*/
-// PackageArchitectureMatchesSpecification				/*{{{*/
+class PackageArchitectureMatchesSpecification : public PackageMatcher {	/*{{{*/
 /** \class PackageArchitectureMatchesSpecification
    \brief matching against architecture specification strings
 
@@ -62,12 +120,9 @@ public:
    debian-policy §11.1 "Architecture specification strings".
 
    Examples: i386, mipsel, linux-any, any-amd64, any */
-class PackageArchitectureMatchesSpecification : public PackageMatcher {
 	std::string literal;
 	std::string complete;
 	bool isPattern;
-	/** \brief dpointer placeholder (for later in case we need it) */
-	void *d;
 public:
 	/** \brief matching against architecture specification strings
 	 *
@@ -79,10 +134,18 @@ public:
 	PackageArchitectureMatchesSpecification(std::string const &pattern, bool const isPattern = true);
 	bool operator() (char const * const &arch);
 	virtual bool operator() (pkgCache::PkgIterator const &Pkg);
-	virtual bool operator() (pkgCache::VerIterator const &Ver);
 	virtual ~PackageArchitectureMatchesSpecification();
 };
 									/*}}}*/
+class PackageIsNewInstall : public PackageMatcher {			/*{{{*/
+	pkgCacheFile * const Cache;
+public:
+	PackageIsNewInstall(pkgCacheFile * const Cache);
+	virtual bool operator() (pkgCache::PkgIterator const &Pkg);
+	virtual ~PackageIsNewInstall();
+};
+									/*}}}*/
+
 }
 }
 #endif

+ 13 - 3
apt-pkg/cacheiterators.h

@@ -159,8 +159,12 @@ class pkgCache::PkgIterator: public Iterator<Package, PkgIterator> {
 	enum OkState {NeedsNothing,NeedsUnpack,NeedsConfigure};
 
 	// Accessors
-	inline const char *Name() const {return S->Name == 0?0:Owner->StrP + S->Name;}
-	inline const char *Section() const {return S->Section == 0?0:Owner->StrP + S->Section;}
+	inline const char *Name() const { return Group().Name(); }
+	// Versions have sections - and packages can have different versions with different sections
+	// so this interface is broken by design. It used to return the section of the "first parsed
+	// package stanza", but as this can potentially be anything it now returns the section of the
+	// newest version instead (if any). aka: Run as fast as you can to Version.Section().
+	APT_DEPRECATED const char *Section() const;
 	inline bool Purge() const {return S->CurrentState == pkgCache::State::Purge ||
 		(S->CurrentVer == 0 && S->CurrentState == pkgCache::State::NotInstalled);}
 	inline const char *Arch() const {return S->Arch == 0?0:Owner->StrP + S->Arch;}
@@ -211,6 +215,12 @@ class pkgCache::VerIterator : public Iterator<Version, VerIterator> {
 	// Accessors
 	inline const char *VerStr() const {return S->VerStr == 0?0:Owner->StrP + S->VerStr;}
 	inline const char *Section() const {return S->Section == 0?0:Owner->StrP + S->Section;}
+	/** \brief source package name this version comes from
+	   Always contains the name, even if it is the same as the binary name */
+	inline const char *SourcePkgName() const {return Owner->StrP + S->SourcePkgName;}
+	/** \brief source version this version comes from
+	   Always contains the version string, even if it is the same as the binary version */
+	inline const char *SourceVerStr() const {return Owner->StrP + S->SourceVerStr;}
 	inline const char *Arch() const {
 		if ((S->MultiArch & pkgCache::Version::All) == pkgCache::Version::All)
 			return "all";
@@ -332,7 +342,7 @@ class pkgCache::PrvIterator : public Iterator<Provides, PrvIterator> {
 	inline void operator ++() {operator ++(0);}
 
 	// Accessors
-	inline const char *Name() const {return Owner->StrP + Owner->PkgP[S->ParentPkg].Name;}
+	inline const char *Name() const {return ParentPkg().Name();}
 	inline const char *ProvideVersion() const {return S->ProvideVersion == 0?0:Owner->StrP + S->ProvideVersion;}
 	inline PkgIterator ParentPkg() const {return PkgIterator(*Owner,Owner->PkgP + S->ParentPkg);}
 	inline VerIterator OwnerVer() const {return VerIterator(*Owner,Owner->VerP + S->Version);}

+ 259 - 110
apt-pkg/cacheset.cc

@@ -24,6 +24,7 @@
 #include <apt-pkg/depcache.h>
 #include <apt-pkg/macros.h>
 #include <apt-pkg/pkgcache.h>
+#include <apt-pkg/fileutl.h>
 
 #include <stddef.h>
 #include <stdio.h>
@@ -36,8 +37,23 @@
 #include <apti18n.h>
 									/*}}}*/
 namespace APT {
-// FromTask - Return all packages in the cache from a specific task	/*{{{*/
-bool PackageContainerInterface::FromTask(PackageContainerInterface * const pci, pkgCacheFile &Cache, std::string pattern, CacheSetHelper &helper) {
+
+// PackageFrom - selecting the appropriate method for package selection	/*{{{*/
+bool CacheSetHelper::PackageFrom(enum PkgSelector const select, PackageContainerInterface * const pci,
+      pkgCacheFile &Cache, std::string const &pattern) {
+	switch (select) {
+	case UNKNOWN: return false;
+	case REGEX: return PackageFromRegEx(pci, Cache, pattern);
+	case TASK: return PackageFromTask(pci, Cache, pattern);
+	case FNMATCH: return PackageFromFnmatch(pci, Cache, pattern);
+	case PACKAGENAME: return PackageFromPackageName(pci, Cache, pattern);
+	case STRING: return PackageFromString(pci, Cache, pattern);
+	}
+	return false;
+}
+									/*}}}*/
+// PackageFromTask - Return all packages in the cache from a specific task /*{{{*/
+bool CacheSetHelper::PackageFromTask(PackageContainerInterface * const pci, pkgCacheFile &Cache, std::string pattern) {
 	size_t const archfound = pattern.find_last_of(':');
 	std::string arch = "native";
 	if (archfound != std::string::npos) {
@@ -54,7 +70,7 @@ bool PackageContainerInterface::FromTask(PackageContainerInterface * const pci,
 
 	bool const wasEmpty = pci->empty();
 	if (wasEmpty == true)
-		pci->setConstructor(TASK);
+		pci->setConstructor(CacheSetHelper::TASK);
 
 	// get the records
 	pkgRecords Recs(Cache);
@@ -90,32 +106,32 @@ bool PackageContainerInterface::FromTask(PackageContainerInterface * const pci,
 			continue;
 
 		pci->insert(Pkg);
-		helper.showTaskSelection(Pkg, pattern);
+		showPackageSelection(Pkg, CacheSetHelper::TASK, pattern);
 		found = true;
 	}
 	regfree(&Pattern);
 
 	if (found == false) {
-		helper.canNotFindTask(pci, Cache, pattern);
-		pci->setConstructor(UNKNOWN);
+		canNotFindPackage(CacheSetHelper::TASK, pci, Cache, pattern);
+		pci->setConstructor(CacheSetHelper::UNKNOWN);
 		return false;
 	}
 
-	if (wasEmpty == false && pci->getConstructor() != UNKNOWN)
-		pci->setConstructor(UNKNOWN);
+	if (wasEmpty == false && pci->getConstructor() != CacheSetHelper::UNKNOWN)
+		pci->setConstructor(CacheSetHelper::UNKNOWN);
 
 	return true;
 }
 									/*}}}*/
-// FromRegEx - Return all packages in the cache matching a pattern	/*{{{*/
-bool PackageContainerInterface::FromRegEx(PackageContainerInterface * const pci, pkgCacheFile &Cache, std::string pattern, CacheSetHelper &helper) {
+// PackageFromRegEx - Return all packages in the cache matching a pattern /*{{{*/
+bool CacheSetHelper::PackageFromRegEx(PackageContainerInterface * const pci, pkgCacheFile &Cache, std::string pattern) {
 	static const char * const isregex = ".?+*|[^$";
 	if (pattern.find_first_of(isregex) == std::string::npos)
 		return false;
 
 	bool const wasEmpty = pci->empty();
 	if (wasEmpty == true)
-		pci->setConstructor(REGEX);
+		pci->setConstructor(CacheSetHelper::REGEX);
 
 	size_t archfound = pattern.find_last_of(':');
 	std::string arch = "native";
@@ -149,28 +165,25 @@ bool PackageContainerInterface::FromRegEx(PackageContainerInterface * const pci,
 		}
 
 		pci->insert(Pkg);
-		helper.showRegExSelection(Pkg, pattern);
+		showPackageSelection(Pkg, CacheSetHelper::REGEX, pattern);
 		found = true;
 	}
 
 	if (found == false) {
-		helper.canNotFindRegEx(pci, Cache, pattern);
-		pci->setConstructor(UNKNOWN);
+		canNotFindPackage(CacheSetHelper::REGEX, pci, Cache, pattern);
+		pci->setConstructor(CacheSetHelper::UNKNOWN);
 		return false;
 	}
 
-	if (wasEmpty == false && pci->getConstructor() != UNKNOWN)
-		pci->setConstructor(UNKNOWN);
+	if (wasEmpty == false && pci->getConstructor() != CacheSetHelper::UNKNOWN)
+		pci->setConstructor(CacheSetHelper::UNKNOWN);
 
 	return true;
 }
 									/*}}}*/
-// FromFnmatch - Returns the package defined  by this fnmatch		/*{{{*/
-bool 
-PackageContainerInterface::FromFnmatch(PackageContainerInterface * const pci, 
-                                       pkgCacheFile &Cache,
-                                       std::string pattern,
-                                       CacheSetHelper &helper)
+// PackageFromFnmatch - Returns the package defined  by this fnmatch	/*{{{*/
+bool CacheSetHelper::PackageFromFnmatch(PackageContainerInterface * const pci,
+                                       pkgCacheFile &Cache, std::string pattern)
 {
 	static const char * const isfnmatch = ".?*[]!";
 	if (pattern.find_first_of(isfnmatch) == std::string::npos)
@@ -178,7 +191,7 @@ PackageContainerInterface::FromFnmatch(PackageContainerInterface * const pci,
 
 	bool const wasEmpty = pci->empty();
 	if (wasEmpty == true)
-		pci->setConstructor(FNMATCH);
+		pci->setConstructor(CacheSetHelper::FNMATCH);
 
 	size_t archfound = pattern.find_last_of(':');
 	std::string arch = "native";
@@ -212,33 +225,25 @@ PackageContainerInterface::FromFnmatch(PackageContainerInterface * const pci,
 		}
 
 		pci->insert(Pkg);
-#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 13)
-		helper.showFnmatchSelection(Pkg, pattern);
-#else
-		helper.showRegExSelection(Pkg, pattern);
-#endif
+		showPackageSelection(Pkg, CacheSetHelper::FNMATCH, pattern);
 		found = true;
 	}
 
 	if (found == false) {
-#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 13)
-		helper.canNotFindFnmatch(pci, Cache, pattern);
-#else
-                helper.canNotFindRegEx(pci, Cache, pattern);
-#endif
-		pci->setConstructor(UNKNOWN);
+		canNotFindPackage(CacheSetHelper::FNMATCH, pci, Cache, pattern);
+		pci->setConstructor(CacheSetHelper::UNKNOWN);
 		return false;
 	}
 
-	if (wasEmpty == false && pci->getConstructor() != UNKNOWN)
-		pci->setConstructor(UNKNOWN);
+	if (wasEmpty == false && pci->getConstructor() != CacheSetHelper::UNKNOWN)
+		pci->setConstructor(CacheSetHelper::UNKNOWN);
 
 	return true;
 }
 									/*}}}*/
-// FromName - Returns the package defined  by this string		/*{{{*/
-pkgCache::PkgIterator PackageContainerInterface::FromName(pkgCacheFile &Cache,
-			std::string const &str, CacheSetHelper &helper) {
+// PackageFromName - Returns the package defined  by this string	/*{{{*/
+pkgCache::PkgIterator CacheSetHelper::PackageFromName(pkgCacheFile &Cache,
+			std::string const &str) {
 	std::string pkg = str;
 	size_t archfound = pkg.find_last_of(':');
 	std::string arch;
@@ -259,13 +264,13 @@ pkgCache::PkgIterator PackageContainerInterface::FromName(pkgCacheFile &Cache,
 		Pkg = Cache.GetPkgCache()->FindPkg(pkg, arch);
 
 	if (Pkg.end() == true)
-		return helper.canNotFindPkgName(Cache, str);
+		return canNotFindPkgName(Cache, str);
 	return Pkg;
 }
 									/*}}}*/
-// FromGroup - Returns the package defined  by this string		/*{{{*/
-bool PackageContainerInterface::FromGroup(PackageContainerInterface * const pci, pkgCacheFile &Cache,
-			std::string pkg, CacheSetHelper &helper) {
+// PackageFromPackageName - Returns the package defined  by this string /*{{{*/
+bool CacheSetHelper::PackageFromPackageName(PackageContainerInterface * const pci, pkgCacheFile &Cache,
+			std::string pkg) {
 	if (unlikely(Cache.GetPkgCache() == 0))
 		return false;
 
@@ -305,7 +310,7 @@ bool PackageContainerInterface::FromGroup(PackageContainerInterface * const pci,
 		}
 	}
 
-	pkgCache::PkgIterator Pkg = helper.canNotFindPkgName(Cache, pkg);
+	pkgCache::PkgIterator Pkg = canNotFindPkgName(Cache, pkg);
 	if (Pkg.end() == true)
 	   return false;
 
@@ -313,20 +318,18 @@ bool PackageContainerInterface::FromGroup(PackageContainerInterface * const pci,
 	return true;
 }
 									/*}}}*/
-// FromString - Return all packages matching a specific string		/*{{{*/
-bool PackageContainerInterface::FromString(PackageContainerInterface * const pci, pkgCacheFile &Cache, std::string const &str, CacheSetHelper &helper) {
+// PackageFromString - Return all packages matching a specific string	/*{{{*/
+bool CacheSetHelper::PackageFromString(PackageContainerInterface * const pci, pkgCacheFile &Cache, std::string const &str) {
 	bool found = true;
 	_error->PushToStack();
 
-	if (FromGroup(pci, Cache, str, helper) == false &&
-		 FromTask(pci, Cache, str, helper) == false &&
-#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 13)
-                 // FIXME: hm, hm, regexp/fnmatch incompatible?
-		 FromFnmatch(pci, Cache, str, helper) == false &&
-#endif
-		 FromRegEx(pci, Cache, str, helper) == false)
+	if (PackageFrom(CacheSetHelper::PACKAGENAME, pci, Cache, str) == false &&
+		 PackageFrom(CacheSetHelper::TASK, pci, Cache, str) == false &&
+		 // FIXME: hm, hm, regexp/fnmatch incompatible?
+		 PackageFrom(CacheSetHelper::FNMATCH, pci, Cache, str) == false &&
+		 PackageFrom(CacheSetHelper::REGEX, pci, Cache, str) == false)
 	{
-		helper.canNotFindPackage(pci, Cache, str);
+		canNotFindPackage(CacheSetHelper::PACKAGENAME, pci, Cache, str);
 		found = false;
 	}
 
@@ -337,51 +340,50 @@ bool PackageContainerInterface::FromString(PackageContainerInterface * const pci
 	return found;
 }
 									/*}}}*/
-// FromCommandLine - Return all packages specified on commandline	/*{{{*/
-bool PackageContainerInterface::FromCommandLine(PackageContainerInterface * const pci, pkgCacheFile &Cache, const char **cmdline, CacheSetHelper &helper) {
+// PackageFromCommandLine - Return all packages specified on commandline /*{{{*/
+bool CacheSetHelper::PackageFromCommandLine(PackageContainerInterface * const pci, pkgCacheFile &Cache, const char **cmdline) {
 	bool found = false;
 	for (const char **I = cmdline; *I != 0; ++I)
-		found |= PackageContainerInterface::FromString(pci, Cache, *I, helper);
+		found |= PackageFrom(CacheSetHelper::PACKAGENAME, pci, Cache, *I);
 	return found;
 }
 									/*}}}*/
 // FromModifierCommandLine - helper doing the work for PKG:GroupedFromCommandLine	/*{{{*/
-bool PackageContainerInterface::FromModifierCommandLine(unsigned short &modID, PackageContainerInterface * const pci,
+bool CacheSetHelper::PackageFromModifierCommandLine(unsigned short &modID, PackageContainerInterface * const pci,
 							pkgCacheFile &Cache, const char * cmdline,
-							std::list<Modifier> const &mods, CacheSetHelper &helper) {
+							std::list<PkgModifier> const &mods) {
 	std::string str = cmdline;
 	unsigned short fallback = modID;
 	bool modifierPresent = false;
-	for (std::list<Modifier>::const_iterator mod = mods.begin();
+	for (std::list<PkgModifier>::const_iterator mod = mods.begin();
 	     mod != mods.end(); ++mod) {
 		size_t const alength = strlen(mod->Alias);
 		switch(mod->Pos) {
-		case Modifier::POSTFIX:
+		case PkgModifier::POSTFIX:
 			if (str.compare(str.length() - alength, alength,
 					mod->Alias, 0, alength) != 0)
 				continue;
 			str.erase(str.length() - alength);
 			modID = mod->ID;
 			break;
-		case Modifier::PREFIX:
+		case PkgModifier::PREFIX:
 			continue;
-		case Modifier::NONE:
+		case PkgModifier::NONE:
 			continue;
 		}
 		modifierPresent = true;
 		break;
 	}
 	if (modifierPresent == true) {
-		bool const errors = helper.showErrors(false);
-		pkgCache::PkgIterator Pkg = FromName(Cache, cmdline, helper);
-		helper.showErrors(errors);
-		if (Pkg.end() == false) {
-			pci->insert(Pkg);
+		bool const errors = showErrors(false);
+		bool const found = PackageFrom(PACKAGENAME, pci, Cache, cmdline);
+		showErrors(errors);
+		if (found == true) {
 			modID = fallback;
 			return true;
 		}
 	}
-	return FromString(pci, Cache, str, helper);
+	return PackageFrom(CacheSetHelper::PACKAGENAME, pci, Cache, str);
 }
 									/*}}}*/
 // FromModifierCommandLine - helper doing the work for VER:GroupedFromCommandLine	/*{{{*/
@@ -390,7 +392,7 @@ bool VersionContainerInterface::FromModifierCommandLine(unsigned short &modID,
 							pkgCacheFile &Cache, const char * cmdline,
 							std::list<Modifier> const &mods,
 							CacheSetHelper &helper) {
-	Version select = NEWEST;
+	CacheSetHelper::VerSelector select = CacheSetHelper::NEWEST;
 	std::string str = cmdline;
 	if (unlikely(str.empty() == true))
 		return false;
@@ -433,7 +435,8 @@ bool VersionContainerInterface::FromModifierCommandLine(unsigned short &modID,
 // FromCommandLine - Return all versions specified on commandline	/*{{{*/
 bool VersionContainerInterface::FromCommandLine(VersionContainerInterface * const vci,
 						pkgCacheFile &Cache, const char **cmdline,
-						Version const &fallback, CacheSetHelper &helper) {
+						CacheSetHelper::VerSelector const fallback,
+						CacheSetHelper &helper) {
 	bool found = false;
 	for (const char **I = cmdline; *I != 0; ++I)
 		found |= VersionContainerInterface::FromString(vci, Cache, *I, fallback, helper);
@@ -443,8 +446,17 @@ bool VersionContainerInterface::FromCommandLine(VersionContainerInterface * cons
 // FromString - Returns all versions spedcified by a string		/*{{{*/
 bool VersionContainerInterface::FromString(VersionContainerInterface * const vci,
 					   pkgCacheFile &Cache, std::string pkg,
-					   Version const &fallback, CacheSetHelper &helper,
+					   CacheSetHelper::VerSelector const fallback,
+					   CacheSetHelper &helper,
 					   bool const onlyFromName) {
+	PackageSet pkgset;
+	if(FileExists(pkg)) {
+		helper.PackageFrom(CacheSetHelper::STRING, &pkgset, Cache, pkg);
+		if(pkgset.empty() == true)
+			return false;
+		return VersionContainerInterface::FromPackage(vci, Cache, pkgset.begin(), fallback, helper);
+	}
+
 	std::string ver;
 	bool verIsRel = false;
 	size_t const vertag = pkg.find_last_of("/=");
@@ -453,15 +465,14 @@ bool VersionContainerInterface::FromString(VersionContainerInterface * const vci
 		verIsRel = (pkg[vertag] == '/');
 		pkg.erase(vertag);
 	}
-	PackageSet pkgset;
 	if (onlyFromName == false)
-		PackageContainerInterface::FromString(&pkgset, Cache, pkg, helper);
+		helper.PackageFrom(CacheSetHelper::STRING, &pkgset, Cache, pkg);
 	else {
-		pkgset.insert(PackageContainerInterface::FromName(Cache, pkg, helper));
+		helper.PackageFrom(CacheSetHelper::PACKAGENAME, &pkgset, Cache, pkg);
 	}
 
 	bool errors = true;
-	if (pkgset.getConstructor() != PackageSet::UNKNOWN)
+	if (pkgset.getConstructor() != CacheSetHelper::UNKNOWN)
 		errors = helper.showErrors(false);
 
 	bool found = false;
@@ -480,7 +491,7 @@ bool VersionContainerInterface::FromString(VersionContainerInterface * const vci
 			if (P->VersionList != 0)
 				V = P.VersionList();
 			else
-				V = helper.canNotFindNewestVer(Cache, P);
+				V = helper.canNotGetVersion(CacheSetHelper::NEWEST, Cache, P);
 		} else {
 			pkgVersionMatch Match(ver, (verIsRel == true ? pkgVersionMatch::Release :
 					pkgVersionMatch::Version));
@@ -497,11 +508,14 @@ bool VersionContainerInterface::FromString(VersionContainerInterface * const vci
 		}
 		if (V.end() == true)
 			continue;
-		helper.showSelectedVersion(P, V, ver, verIsRel);
+		if (verIsRel == true)
+			helper.showVersionSelection(P, V, CacheSetHelper::RELEASE, ver);
+		else
+			helper.showVersionSelection(P, V, CacheSetHelper::VERSIONNUMBER, ver);
 		vci->insert(V);
 		found = true;
 	}
-	if (pkgset.getConstructor() != PackageSet::UNKNOWN)
+	if (pkgset.getConstructor() != CacheSetHelper::UNKNOWN)
 		helper.showErrors(errors);
 	return found;
 }
@@ -510,30 +524,30 @@ bool VersionContainerInterface::FromString(VersionContainerInterface * const vci
 bool VersionContainerInterface::FromPackage(VersionContainerInterface * const vci,
 					    pkgCacheFile &Cache,
 					    pkgCache::PkgIterator const &P,
-					    Version const &fallback,
+					    CacheSetHelper::VerSelector const fallback,
 					    CacheSetHelper &helper) {
 	pkgCache::VerIterator V;
 	bool showErrors;
 	bool found = false;
 	switch(fallback) {
-	case ALL:
+	case CacheSetHelper::ALL:
 		if (P->VersionList != 0)
 			for (V = P.VersionList(); V.end() != true; ++V)
 				found |= vci->insert(V);
 		else
-			helper.canNotFindAllVer(vci, Cache, P);
+			helper.canNotFindVersion(CacheSetHelper::ALL, vci, Cache, P);
 		break;
-	case CANDANDINST:
+	case CacheSetHelper::CANDANDINST:
 		found |= vci->insert(getInstalledVer(Cache, P, helper));
 		found |= vci->insert(getCandidateVer(Cache, P, helper));
 		break;
-	case CANDIDATE:
+	case CacheSetHelper::CANDIDATE:
 		found |= vci->insert(getCandidateVer(Cache, P, helper));
 		break;
-	case INSTALLED:
+	case CacheSetHelper::INSTALLED:
 		found |= vci->insert(getInstalledVer(Cache, P, helper));
 		break;
-	case CANDINST:
+	case CacheSetHelper::CANDINST:
 		showErrors = helper.showErrors(false);
 		V = getCandidateVer(Cache, P, helper);
 		if (V.end() == true)
@@ -542,9 +556,9 @@ bool VersionContainerInterface::FromPackage(VersionContainerInterface * const vc
 		if (V.end() == false)
 			found |= vci->insert(V);
 		else
-			helper.canNotFindInstCandVer(vci, Cache, P);
+			helper.canNotFindVersion(CacheSetHelper::CANDINST, vci, Cache, P);
 		break;
-	case INSTCAND:
+	case CacheSetHelper::INSTCAND:
 		showErrors = helper.showErrors(false);
 		V = getInstalledVer(Cache, P, helper);
 		if (V.end() == true)
@@ -553,14 +567,18 @@ bool VersionContainerInterface::FromPackage(VersionContainerInterface * const vc
 		if (V.end() == false)
 			found |= vci->insert(V);
 		else
-			helper.canNotFindInstCandVer(vci, Cache, P);
+			helper.canNotFindVersion(CacheSetHelper::INSTCAND, vci, Cache, P);
 		break;
-	case NEWEST:
+	case CacheSetHelper::NEWEST:
 		if (P->VersionList != 0)
 			found |= vci->insert(P.VersionList());
 		else
-			helper.canNotFindNewestVer(Cache, P);
+			helper.canNotFindVersion(CacheSetHelper::NEWEST, vci, Cache, P);
 		break;
+	case CacheSetHelper::RELEASE:
+	case CacheSetHelper::VERSIONNUMBER:
+		// both make no sense here, so always false
+		return false;
 	}
 	return found;
 }
@@ -577,7 +595,7 @@ pkgCache::VerIterator VersionContainerInterface::getCandidateVer(pkgCacheFile &C
 		Cand = Cache[Pkg].CandidateVerIter(Cache);
 	}
 	if (Cand.end() == true)
-		return helper.canNotFindCandidateVer(Cache, Pkg);
+		return helper.canNotGetVersion(CacheSetHelper::CANDIDATE, Cache, Pkg);
 	return Cand;
 }
 									/*}}}*/
@@ -585,19 +603,31 @@ pkgCache::VerIterator VersionContainerInterface::getCandidateVer(pkgCacheFile &C
 pkgCache::VerIterator VersionContainerInterface::getInstalledVer(pkgCacheFile &Cache,
 		pkgCache::PkgIterator const &Pkg, CacheSetHelper &helper) {
 	if (Pkg->CurrentVer == 0)
-		return helper.canNotFindInstalledVer(Cache, Pkg);
+		return helper.canNotGetVersion(CacheSetHelper::INSTALLED, Cache, Pkg);
 	return Pkg.CurrentVer();
 }
 									/*}}}*/
 
-// canNotFindPkgName - handle the case no package has this name		/*{{{*/
-pkgCache::PkgIterator CacheSetHelper::canNotFindPkgName(pkgCacheFile &Cache,
-			std::string const &str) {
-	if (ShowError == true)
-		_error->Insert(ErrorType, _("Unable to locate package %s"), str.c_str());
-	return pkgCache::PkgIterator(Cache, 0);
+// canNotFindPackage - with the given selector and pattern		/*{{{*/
+void CacheSetHelper::canNotFindPackage(enum PkgSelector const select,
+      PackageContainerInterface * const pci, pkgCacheFile &Cache,
+      std::string const &pattern) {
+	switch (select) {
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic push
+	#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+	case REGEX: canNotFindRegEx(pci, Cache, pattern); break;
+	case TASK: canNotFindTask(pci, Cache, pattern); break;
+	case FNMATCH: canNotFindFnmatch(pci, Cache, pattern); break;
+	case PACKAGENAME: canNotFindPackage(pci, Cache, pattern); break;
+	case STRING: canNotFindPackage(pci, Cache, pattern); break;
+	case UNKNOWN: break;
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic pop
+#endif
+	}
 }
-									/*}}}*/
 // canNotFindTask - handle the case no package is found for a task	/*{{{*/
 void CacheSetHelper::canNotFindTask(PackageContainerInterface * const /*pci*/, pkgCacheFile &/*Cache*/, std::string pattern) {
 	if (ShowError == true)
@@ -609,17 +639,50 @@ void CacheSetHelper::canNotFindRegEx(PackageContainerInterface * const /*pci*/,
 	if (ShowError == true)
 		_error->Insert(ErrorType, _("Couldn't find any package by regex '%s'"), pattern.c_str());
 }
-#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 13)
+									/*}}}*/
 // canNotFindFnmatch - handle the case no package is found by a fnmatch	/*{{{*/
    void CacheSetHelper::canNotFindFnmatch(PackageContainerInterface * const /*pci*/, pkgCacheFile &/*Cache*/, std::string pattern) {
 	if (ShowError == true)
 		_error->Insert(ErrorType, _("Couldn't find any package by glob '%s'"), pattern.c_str());
 }
-#endif									/*}}}*/
+									/*}}}*/
 // canNotFindPackage - handle the case no package is found from a string/*{{{*/
 APT_CONST void CacheSetHelper::canNotFindPackage(PackageContainerInterface * const /*pci*/, pkgCacheFile &/*Cache*/, std::string const &/*str*/) {
 }
 									/*}}}*/
+									/*}}}*/
+// canNotFindPkgName - handle the case no package has this name		/*{{{*/
+pkgCache::PkgIterator CacheSetHelper::canNotFindPkgName(pkgCacheFile &Cache,
+			std::string const &str) {
+	if (ShowError == true)
+		_error->Insert(ErrorType, _("Unable to locate package %s"), str.c_str());
+	return pkgCache::PkgIterator(Cache, 0);
+}
+									/*}}}*/
+// canNotFindVersion - for package by selector				/*{{{*/
+void CacheSetHelper::canNotFindVersion(enum VerSelector const select, VersionContainerInterface * const vci, pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg)
+{
+	switch (select) {
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic push
+	#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+	case ALL: canNotFindAllVer(vci, Cache, Pkg); break;
+	case INSTCAND: canNotFindInstCandVer(vci, Cache, Pkg); break;
+	case CANDINST: canNotFindCandInstVer(vci, Cache, Pkg); break;
+	case NEWEST: canNotFindNewestVer(Cache, Pkg); break;
+	case CANDIDATE: canNotFindCandidateVer(Cache, Pkg); break;
+	case INSTALLED: canNotFindInstalledVer(Cache, Pkg); break;
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic pop
+#endif
+	case CANDANDINST: canNotGetCandInstVer(Cache, Pkg); break;
+	case RELEASE:
+	case VERSIONNUMBER:
+		// invalid in this branch
+		break;
+	}
+}
 // canNotFindAllVer							/*{{{*/
 void CacheSetHelper::canNotFindAllVer(VersionContainerInterface * const /*vci*/, pkgCacheFile &/*Cache*/,
 		pkgCache::PkgIterator const &Pkg) {
@@ -628,19 +691,42 @@ void CacheSetHelper::canNotFindAllVer(VersionContainerInterface * const /*vci*/,
 }
 									/*}}}*/
 // canNotFindInstCandVer						/*{{{*/
-void CacheSetHelper::canNotFindInstCandVer(VersionContainerInterface * const /*vci*/, pkgCacheFile &/*Cache*/,
+void CacheSetHelper::canNotFindInstCandVer(VersionContainerInterface * const /*vci*/, pkgCacheFile &Cache,
 		pkgCache::PkgIterator const &Pkg) {
-	if (ShowError == true)
-		_error->Insert(ErrorType, _("Can't select installed nor candidate version from package '%s' as it has neither of them"), Pkg.FullName(true).c_str());
+	canNotGetInstCandVer(Cache, Pkg);
 }
 									/*}}}*/
 // canNotFindInstCandVer						/*{{{*/
-void CacheSetHelper::canNotFindCandInstVer(VersionContainerInterface * const /*vci*/, pkgCacheFile &/*Cache*/,
+void CacheSetHelper::canNotFindCandInstVer(VersionContainerInterface * const /*vci*/, pkgCacheFile &Cache,
 		pkgCache::PkgIterator const &Pkg) {
-	if (ShowError == true)
-		_error->Insert(ErrorType, _("Can't select installed nor candidate version from package '%s' as it has neither of them"), Pkg.FullName(true).c_str());
+	canNotGetCandInstVer(Cache, Pkg);
 }
 									/*}}}*/
+									/*}}}*/
+// canNotGetVersion - for package by selector				/*{{{*/
+pkgCache::VerIterator CacheSetHelper::canNotGetVersion(enum VerSelector const select, pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg) {
+	switch (select) {
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic push
+	#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+	case NEWEST: return canNotFindNewestVer(Cache, Pkg);
+	case CANDIDATE: return canNotFindCandidateVer(Cache, Pkg);
+	case INSTALLED: return canNotFindInstalledVer(Cache, Pkg);
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic pop
+#endif
+	case CANDINST: return canNotGetCandInstVer(Cache, Pkg);
+	case INSTCAND: return canNotGetInstCandVer(Cache, Pkg);
+	case ALL:
+	case CANDANDINST:
+	case RELEASE:
+	case VERSIONNUMBER:
+		// invalid in this branch
+		return pkgCache::VerIterator(Cache, 0);
+	}
+	return pkgCache::VerIterator(Cache, 0);
+}
 // canNotFindNewestVer							/*{{{*/
 pkgCache::VerIterator CacheSetHelper::canNotFindNewestVer(pkgCacheFile &Cache,
 		pkgCache::PkgIterator const &Pkg) {
@@ -665,6 +751,42 @@ pkgCache::VerIterator CacheSetHelper::canNotFindInstalledVer(pkgCacheFile &Cache
 	return pkgCache::VerIterator(Cache, 0);
 }
 									/*}}}*/
+// canNotFindInstCandVer						/*{{{*/
+pkgCache::VerIterator CacheSetHelper::canNotGetInstCandVer(pkgCacheFile &Cache,
+		pkgCache::PkgIterator const &Pkg) {
+	if (ShowError == true)
+		_error->Insert(ErrorType, _("Can't select installed nor candidate version from package '%s' as it has neither of them"), Pkg.FullName(true).c_str());
+	return pkgCache::VerIterator(Cache, 0);
+}
+									/*}}}*/
+// canNotFindInstCandVer						/*{{{*/
+pkgCache::VerIterator CacheSetHelper::canNotGetCandInstVer(pkgCacheFile &Cache,
+		pkgCache::PkgIterator const &Pkg) {
+	if (ShowError == true)
+		_error->Insert(ErrorType, _("Can't select installed nor candidate version from package '%s' as it has neither of them"), Pkg.FullName(true).c_str());
+	return pkgCache::VerIterator(Cache, 0);
+}
+									/*}}}*/
+									/*}}}*/
+// showPackageSelection - by selector and given pattern			/*{{{*/
+APT_CONST void CacheSetHelper::showPackageSelection(pkgCache::PkgIterator const &pkg, enum PkgSelector const select,
+				       std::string const &pattern) {
+	switch (select) {
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic push
+	#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+	case REGEX: showRegExSelection(pkg, pattern); break;
+	case TASK: showTaskSelection(pkg, pattern); break;
+	case FNMATCH: showFnmatchSelection(pkg, pattern); break;
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic pop
+#endif
+	case PACKAGENAME: /* no suprises here */ break;
+	case STRING: /* handled by the special cases */ break;
+	case UNKNOWN: break;
+	}
+}
 // showTaskSelection							/*{{{*/
 APT_CONST void CacheSetHelper::showTaskSelection(pkgCache::PkgIterator const &/*pkg*/,
 				       std::string const &/*pattern*/) {
@@ -675,14 +797,41 @@ APT_CONST void CacheSetHelper::showRegExSelection(pkgCache::PkgIterator const &/
 					std::string const &/*pattern*/) {
 }
 									/*}}}*/
-#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 13)
 // showFnmatchSelection							/*{{{*/
 APT_CONST void CacheSetHelper::showFnmatchSelection(pkgCache::PkgIterator const &/*pkg*/,
                                          std::string const &/*pattern*/) {
 }
 									/*}}}*/
+									/*}}}*/
+// showVersionSelection							/*{{{*/
+APT_CONST void CacheSetHelper::showVersionSelection(pkgCache::PkgIterator const &Pkg,
+      pkgCache::VerIterator const &Ver, enum VerSelector const select, std::string const &pattern) {
+	switch (select) {
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic push
+	#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
 #endif
-// showSelectedVersion							/*{{{*/
+	case RELEASE:
+		showSelectedVersion(Pkg, Ver, pattern, true);
+		break;
+	case VERSIONNUMBER:
+		showSelectedVersion(Pkg, Ver, pattern, false);
+		break;
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic pop
+	#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+	case NEWEST:
+	case CANDIDATE:
+	case INSTALLED:
+	case CANDINST:
+	case INSTCAND:
+	case ALL:
+	case CANDANDINST:
+		// not really suprises, but in fact: just not implemented
+		break;
+	}
+}
 APT_CONST void CacheSetHelper::showSelectedVersion(pkgCache::PkgIterator const &/*Pkg*/,
 					 pkgCache::VerIterator const /*Ver*/,
 					 std::string const &/*ver*/,

+ 475 - 105
apt-pkg/cacheset.h

@@ -13,8 +13,10 @@
 #include <map>
 #include <set>
 #include <list>
+#include <vector>
 #include <string>
 #include <iterator>
+#include <algorithm>
 
 #include <stddef.h>
 
@@ -51,36 +53,127 @@ public:									/*{{{*/
 			ShowError(ShowError), ErrorType(ErrorType) {}
 	virtual ~CacheSetHelper() {}
 
-	virtual void showTaskSelection(pkgCache::PkgIterator const &pkg, std::string const &pattern);
-	virtual void showRegExSelection(pkgCache::PkgIterator const &pkg, std::string const &pattern);
-#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 13)
-	virtual void showFnmatchSelection(pkgCache::PkgIterator const &pkg, std::string const &pattern);
-#endif
-	virtual void showSelectedVersion(pkgCache::PkgIterator const &Pkg, pkgCache::VerIterator const Ver,
-				 std::string const &ver, bool const verIsRel);
+	enum PkgSelector { UNKNOWN, REGEX, TASK, FNMATCH, PACKAGENAME, STRING };
 
-	virtual void canNotFindTask(PackageContainerInterface * const pci, pkgCacheFile &Cache, std::string pattern);
-	virtual void canNotFindRegEx(PackageContainerInterface * const pci, pkgCacheFile &Cache, std::string pattern);
-#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 13)
-	virtual void canNotFindFnmatch(PackageContainerInterface * const pci, pkgCacheFile &Cache, std::string pattern);
-#endif
-	virtual void canNotFindPackage(PackageContainerInterface * const pci, pkgCacheFile &Cache, std::string const &str);
+	virtual bool PackageFrom(enum PkgSelector const select, PackageContainerInterface * const pci, pkgCacheFile &Cache, std::string const &pattern);
+
+	virtual bool PackageFromCommandLine(PackageContainerInterface * const pci, pkgCacheFile &Cache, const char **cmdline);
+
+	struct PkgModifier {
+		enum Position { NONE, PREFIX, POSTFIX };
+		unsigned short ID;
+		const char * const Alias;
+		Position Pos;
+		PkgModifier (unsigned short const &id, const char * const alias, Position const &pos) : ID(id), Alias(alias), Pos(pos) {}
+	};
+	virtual bool PackageFromModifierCommandLine(unsigned short &modID, PackageContainerInterface * const pci,
+					    pkgCacheFile &Cache, const char * cmdline,
+					    std::list<PkgModifier> const &mods);
+
+	// use PackageFrom(PACKAGENAME, …) instead
+	APT_DEPRECATED pkgCache::PkgIterator PackageFromName(pkgCacheFile &Cache, std::string const &pattern);
+
+	/** \brief be notified about the package being selected via pattern
+	 *
+	 * Main use is probably to show a message to the user what happened
+	 *
+	 * \param pkg is the package which was selected
+	 * \param select is the selection method which choose the package
+	 * \param pattern is the string used by the selection method to pick the package
+	 */
+	virtual void showPackageSelection(pkgCache::PkgIterator const &pkg, PkgSelector const select, std::string const &pattern);
+	// use the method above instead, react only on the type you need and let the base handle the rest if need be
+	// this allows use to add new selection methods without breaking the ABI constantly with new virtual methods
+	APT_DEPRECATED virtual void showTaskSelection(pkgCache::PkgIterator const &pkg, std::string const &pattern);
+	APT_DEPRECATED virtual void showRegExSelection(pkgCache::PkgIterator const &pkg, std::string const &pattern);
+	APT_DEPRECATED virtual void showFnmatchSelection(pkgCache::PkgIterator const &pkg, std::string const &pattern);
+
+	/** \brief be notified if a package can't be found via pattern
+	 *
+	 * Can be used to show a message as well as to try something else to make it match
+	 *
+	 * \param select is the method tried for selection
+	 * \param pci is the container the package should be inserted in
+	 * \param Cache is the package universe available
+	 * \param pattern is the string not matching anything
+	 */
+	virtual void canNotFindPackage(enum PkgSelector const select, PackageContainerInterface * const pci, pkgCacheFile &Cache, std::string const &pattern);
+	// same as above for showPackageSelection
+	APT_DEPRECATED virtual void canNotFindTask(PackageContainerInterface * const pci, pkgCacheFile &Cache, std::string pattern);
+	APT_DEPRECATED virtual void canNotFindRegEx(PackageContainerInterface * const pci, pkgCacheFile &Cache, std::string pattern);
+	APT_DEPRECATED virtual void canNotFindFnmatch(PackageContainerInterface * const pci, pkgCacheFile &Cache, std::string pattern);
+	APT_DEPRECATED virtual void canNotFindPackage(PackageContainerInterface * const pci, pkgCacheFile &Cache, std::string const &str);
+
+	/** \brief specifies which version(s) we want to refer to */
+	enum VerSelector {
+		/** by release string */
+		RELEASE,
+		/** by version number string */
+		VERSIONNUMBER,
+		/** All versions */
+		ALL,
+		/** Candidate and installed version */
+		CANDANDINST,
+		/** Candidate version */
+		CANDIDATE,
+		/** Installed version */
+		INSTALLED,
+		/** Candidate or if non installed version */
+		CANDINST,
+		/** Installed or if non candidate version */
+		INSTCAND,
+		/** Newest version */
+		NEWEST
+	};
+
+	/** \brief be notified about the version being selected via pattern
+	 *
+	 * Main use is probably to show a message to the user what happened
+	 * Note that at the moment this method is only called for RELEASE
+	 * and VERSION selections, not for the others.
+	 *
+	 * \param Pkg is the package which was selected for
+	 * \param Ver is the version selected
+	 * \param select is the selection method which choose the version
+	 * \param pattern is the string used by the selection method to pick the version
+	 */
+	virtual void showVersionSelection(pkgCache::PkgIterator const &Pkg, pkgCache::VerIterator const &Ver,
+	      enum VerSelector const select, std::string const &pattern);
+	// renamed to have a similar interface to showPackageSelection
+	APT_DEPRECATED virtual void showSelectedVersion(pkgCache::PkgIterator const &Pkg, pkgCache::VerIterator const Ver,
+				 std::string const &ver, bool const verIsRel);
 
-	virtual void canNotFindAllVer(VersionContainerInterface * const vci, pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg);
-	virtual void canNotFindInstCandVer(VersionContainerInterface * const vci, pkgCacheFile &Cache,
+	/** \brief be notified if a version can't be found for a package
+	 *
+	 * Main use is probably to show a message to the user what happened
+	 *
+	 * \param select is the method tried for selection
+	 * \param vci is the container the version should be inserted in
+	 * \param Cache is the package universe available
+	 * \param Pkg is the package we wanted a version from
+	 */
+	virtual void canNotFindVersion(enum VerSelector const select, VersionContainerInterface * const vci, pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg);
+	// same as above for showPackageSelection
+	APT_DEPRECATED virtual void canNotFindAllVer(VersionContainerInterface * const vci, pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg);
+	APT_DEPRECATED virtual void canNotFindInstCandVer(VersionContainerInterface * const vci, pkgCacheFile &Cache,
 				pkgCache::PkgIterator const &Pkg);
-	virtual void canNotFindCandInstVer(VersionContainerInterface * const vci,
+	APT_DEPRECATED virtual void canNotFindCandInstVer(VersionContainerInterface * const vci,
 				pkgCacheFile &Cache,
 				pkgCache::PkgIterator const &Pkg);
 
-	virtual pkgCache::PkgIterator canNotFindPkgName(pkgCacheFile &Cache, std::string const &str);
-	virtual pkgCache::VerIterator canNotFindNewestVer(pkgCacheFile &Cache,
+	// the difference between canNotFind and canNotGet is that the later is more low-level
+	// and called from other places: In this case looking into the code is the only real answer…
+	virtual pkgCache::VerIterator canNotGetVersion(enum VerSelector const select, pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg);
+	// same as above for showPackageSelection
+	APT_DEPRECATED virtual pkgCache::VerIterator canNotFindNewestVer(pkgCacheFile &Cache,
 				pkgCache::PkgIterator const &Pkg);
-	virtual pkgCache::VerIterator canNotFindCandidateVer(pkgCacheFile &Cache,
+	APT_DEPRECATED virtual pkgCache::VerIterator canNotFindCandidateVer(pkgCacheFile &Cache,
 				pkgCache::PkgIterator const &Pkg);
-	virtual pkgCache::VerIterator canNotFindInstalledVer(pkgCacheFile &Cache,
+	APT_DEPRECATED virtual pkgCache::VerIterator canNotFindInstalledVer(pkgCacheFile &Cache,
 				pkgCache::PkgIterator const &Pkg);
 
+	virtual pkgCache::PkgIterator canNotFindPkgName(pkgCacheFile &Cache, std::string const &str);
+
 	bool showErrors() const { return ShowError; }
 	bool showErrors(bool const newValue) { if (ShowError == newValue) return ShowError; else return ((ShowError = newValue) == false); }
 	GlobalError::MsgType errorType() const { return ErrorType; }
@@ -98,7 +191,19 @@ public:									/*{{{*/
 protected:
 	bool ShowError;
 	GlobalError::MsgType ErrorType;
+
+	pkgCache::VerIterator canNotGetInstCandVer(pkgCacheFile &Cache,
+		pkgCache::PkgIterator const &Pkg);
+	pkgCache::VerIterator canNotGetCandInstVer(pkgCacheFile &Cache,
+		pkgCache::PkgIterator const &Pkg);
+
+	bool PackageFromTask(PackageContainerInterface * const pci, pkgCacheFile &Cache, std::string pattern);
+	bool PackageFromRegEx(PackageContainerInterface * const pci, pkgCacheFile &Cache, std::string pattern);
+	bool PackageFromFnmatch(PackageContainerInterface * const pci, pkgCacheFile &Cache, std::string pattern);
+	bool PackageFromPackageName(PackageContainerInterface * const pci, pkgCacheFile &Cache, std::string pattern);
+	bool PackageFromString(PackageContainerInterface * const pci, pkgCacheFile &Cache, std::string const &pattern);
 };									/*}}}*/
+
 class PackageContainerInterface {					/*{{{*/
 /** \class PackageContainerInterface
 
@@ -118,7 +223,16 @@ public:
 		inline const char *Name() const {return getPkg().Name(); }
 		inline std::string FullName(bool const Pretty) const { return getPkg().FullName(Pretty); }
 		inline std::string FullName() const { return getPkg().FullName(); }
-		inline const char *Section() const {return getPkg().Section(); }
+		APT_DEPRECATED inline const char *Section() const {
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic push
+	#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+	   return getPkg().Section();
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic pop
+#endif
+		}
 		inline bool Purge() const {return getPkg().Purge(); }
 		inline const char *Arch() const {return getPkg().Arch(); }
 		inline pkgCache::GrpIterator Group() const { return getPkg().Group(); }
@@ -142,29 +256,56 @@ public:
 	virtual bool empty() const = 0;
 	virtual void clear() = 0;
 
-	enum Constructor { UNKNOWN, REGEX, TASK, FNMATCH };
-	virtual void setConstructor(Constructor const &con) = 0;
-	virtual Constructor getConstructor() const = 0;
-
-	static bool FromTask(PackageContainerInterface * const pci, pkgCacheFile &Cache, std::string pattern, CacheSetHelper &helper);
-	static bool FromRegEx(PackageContainerInterface * const pci, pkgCacheFile &Cache, std::string pattern, CacheSetHelper &helper);
-	static pkgCache::PkgIterator FromName(pkgCacheFile &Cache, std::string const &pattern, CacheSetHelper &helper);
-	static bool FromFnmatch(PackageContainerInterface * const pci, pkgCacheFile &Cache, std::string pattern, CacheSetHelper &helper);
-	static bool FromGroup(PackageContainerInterface * const pci, pkgCacheFile &Cache, std::string pattern, CacheSetHelper &helper);
-	static bool FromString(PackageContainerInterface * const pci, pkgCacheFile &Cache, std::string const &pattern, CacheSetHelper &helper);
-	static bool FromCommandLine(PackageContainerInterface * const pci, pkgCacheFile &Cache, const char **cmdline, CacheSetHelper &helper);
+	// FIXME: This is a bloody hack removed soon. Use CacheSetHelper::PkgSelector !
+	enum APT_DEPRECATED Constructor { UNKNOWN = CacheSetHelper::UNKNOWN,
+		REGEX = CacheSetHelper::REGEX,
+		TASK = CacheSetHelper::TASK,
+		FNMATCH = CacheSetHelper::FNMATCH };
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic push
+	#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+	void setConstructor(Constructor const by) { ConstructedBy = (CacheSetHelper::PkgSelector)by; }
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic pop
+#endif
 
-	struct Modifier {
-		enum Position { NONE, PREFIX, POSTFIX };
-		unsigned short ID;
-		const char * const Alias;
-		Position Pos;
-		Modifier (unsigned short const &id, const char * const alias, Position const &pos) : ID(id), Alias(alias), Pos(pos) {}
-	};
+	void setConstructor(CacheSetHelper::PkgSelector const by) { ConstructedBy = by; }
+	CacheSetHelper::PkgSelector getConstructor() const { return ConstructedBy; }
+	PackageContainerInterface() : ConstructedBy(CacheSetHelper::UNKNOWN) {}
+	PackageContainerInterface(CacheSetHelper::PkgSelector const by) : ConstructedBy(by) {}
+
+	APT_DEPRECATED static bool FromTask(PackageContainerInterface * const pci, pkgCacheFile &Cache, std::string pattern, CacheSetHelper &helper) {
+	   return helper.PackageFrom(CacheSetHelper::TASK, pci, Cache, pattern); }
+	APT_DEPRECATED static bool FromRegEx(PackageContainerInterface * const pci, pkgCacheFile &Cache, std::string pattern, CacheSetHelper &helper) {
+	   return helper.PackageFrom(CacheSetHelper::REGEX, pci, Cache, pattern); }
+	APT_DEPRECATED static bool FromFnmatch(PackageContainerInterface * const pci, pkgCacheFile &Cache, std::string pattern, CacheSetHelper &helper) {
+	   return helper.PackageFrom(CacheSetHelper::FNMATCH, pci, Cache, pattern); }
+	APT_DEPRECATED static bool FromGroup(PackageContainerInterface * const pci, pkgCacheFile &Cache, std::string pattern, CacheSetHelper &helper) {
+	   return helper.PackageFrom(CacheSetHelper::PACKAGENAME, pci, Cache, pattern); }
+	APT_DEPRECATED static bool FromString(PackageContainerInterface * const pci, pkgCacheFile &Cache, std::string const &pattern, CacheSetHelper &helper) {
+	   return helper.PackageFrom(CacheSetHelper::STRING, pci, Cache, pattern); }
+	APT_DEPRECATED static bool FromCommandLine(PackageContainerInterface * const pci, pkgCacheFile &Cache, const char **cmdline, CacheSetHelper &helper) {
+	   return helper.PackageFromCommandLine(pci, Cache, cmdline); }
+
+	APT_DEPRECATED typedef CacheSetHelper::PkgModifier Modifier;
+
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic push
+	#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+	APT_DEPRECATED static pkgCache::PkgIterator FromName(pkgCacheFile &Cache, std::string const &pattern, CacheSetHelper &helper) {
+	   return helper.PackageFromName(Cache, pattern); }
+	APT_DEPRECATED static bool FromModifierCommandLine(unsigned short &modID, PackageContainerInterface * const pci,
+	      pkgCacheFile &Cache, const char * cmdline,
+	      std::list<Modifier> const &mods, CacheSetHelper &helper) {
+	   return helper.PackageFromModifierCommandLine(modID, pci, Cache, cmdline, mods); }
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic pop
+#endif
 
-	static bool FromModifierCommandLine(unsigned short &modID, PackageContainerInterface * const pci,
-					    pkgCacheFile &Cache, const char * cmdline,
-					    std::list<Modifier> const &mods, CacheSetHelper &helper);
+private:
+	CacheSetHelper::PkgSelector ConstructedBy;
 };
 									/*}}}*/
 template<class Container> class PackageContainer : public PackageContainerInterface {/*{{{*/
@@ -228,11 +369,28 @@ public:									/*{{{*/
 	iterator end() { return iterator(_cont.end()); }
 	const_iterator find(pkgCache::PkgIterator const &P) const { return const_iterator(_cont.find(P)); }
 
-	void setConstructor(Constructor const &by) { ConstructedBy = by; }
-	Constructor getConstructor() const { return ConstructedBy; }
+	PackageContainer() : PackageContainerInterface() {}
+	PackageContainer(CacheSetHelper::PkgSelector const &by) : PackageContainerInterface(by) {}
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic push
+	#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+	APT_DEPRECATED PackageContainer(Constructor const &by) : PackageContainerInterface((CacheSetHelper::PkgSelector)by) {}
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic pop
+#endif
+
+	/** \brief sort all included versions with given comparer
 
-	PackageContainer() : ConstructedBy(UNKNOWN) {}
-	PackageContainer(Constructor const &by) : ConstructedBy(by) {}
+	    Some containers are sorted by default, some are not and can't be,
+	    but a few like std::vector can be sorted if need be, so this can be
+	    specialized in later on. The default is that this will fail though.
+	    Specifically, already sorted containers like std::set will return
+	    false as well as there is no easy way to check that the given comparer
+	    would sort in the same way the set is currently sorted
+
+	    \return \b true if the set was sorted, \b false if not. */
+	template<class Compare> bool sort(Compare /*Comp*/) { return false; }
 
 	/** \brief returns all packages in the cache who belong to the given task
 
@@ -243,8 +401,8 @@ public:									/*{{{*/
 	    \param pattern name of the task
 	    \param helper responsible for error and message handling */
 	static PackageContainer FromTask(pkgCacheFile &Cache, std::string const &pattern, CacheSetHelper &helper) {
-		PackageContainer cont(TASK);
-		PackageContainerInterface::FromTask(&cont, Cache, pattern, helper);
+		PackageContainer cont(CacheSetHelper::TASK);
+		helper.PackageFrom(CacheSetHelper::TASK, &cont, Cache, pattern);
 		return cont;
 	}
 	static PackageContainer FromTask(pkgCacheFile &Cache, std::string const &pattern) {
@@ -260,9 +418,9 @@ public:									/*{{{*/
 	    \param Cache the packages are in
 	    \param pattern regular expression for package names
 	    \param helper responsible for error and message handling */
-	static PackageContainer FromRegEx(pkgCacheFile &Cache, std::string pattern, CacheSetHelper &helper) {
-		PackageContainer cont(REGEX);
-		PackageContainerInterface::FromRegEx(&cont, Cache, pattern, helper);
+	static PackageContainer FromRegEx(pkgCacheFile &Cache, std::string const &pattern, CacheSetHelper &helper) {
+		PackageContainer cont(CacheSetHelper::REGEX);
+		helper.PackageFrom(CacheSetHelper::REGEX, &cont, Cache, pattern);
 		return cont;
 	}
 
@@ -271,9 +429,9 @@ public:									/*{{{*/
 		return FromRegEx(Cache, pattern, helper);
 	}
 
-	static PackageContainer FromFnmatch(pkgCacheFile &Cache, std::string pattern, CacheSetHelper &helper) {
-		PackageContainer cont(FNMATCH);
-		PackageContainerInterface::FromFnmatch(&cont, Cache, pattern, helper);
+	static PackageContainer FromFnmatch(pkgCacheFile &Cache, std::string const &pattern, CacheSetHelper &helper) {
+		PackageContainer cont(CacheSetHelper::FNMATCH);
+		helper.PackageFrom(CacheSetHelper::FNMATCH, &cont, Cache, pattern);
 		return cont;
 	}
 	static PackageContainer FromFnMatch(pkgCacheFile &Cache, std::string const &pattern) {
@@ -281,18 +439,25 @@ public:									/*{{{*/
 		return FromFnmatch(Cache, pattern, helper);
 	}
 
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic push
+	#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
 	/** \brief returns a package specified by a string
 
 	    \param Cache the package is in
 	    \param pattern String the package name should be extracted from
 	    \param helper responsible for error and message handling */
-	static pkgCache::PkgIterator FromName(pkgCacheFile &Cache, std::string const &pattern, CacheSetHelper &helper) {
-		return PackageContainerInterface::FromName(Cache, pattern, helper);
+	APT_DEPRECATED static pkgCache::PkgIterator FromName(pkgCacheFile &Cache, std::string const &pattern, CacheSetHelper &helper) {
+		return helper.PackageFromName(Cache, pattern);
 	}
-	static pkgCache::PkgIterator FromName(pkgCacheFile &Cache, std::string const &pattern) {
+	APT_DEPRECATED static pkgCache::PkgIterator FromName(pkgCacheFile &Cache, std::string const &pattern) {
 		CacheSetHelper helper;
-		return PackageContainerInterface::FromName(Cache, pattern, helper);
+		return FromName(Cache, pattern, helper);
 	}
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic pop
+#endif
 
 	/** \brief returns all packages specified by a string
 
@@ -301,7 +466,7 @@ public:									/*{{{*/
 	    \param helper responsible for error and message handling */
 	static PackageContainer FromString(pkgCacheFile &Cache, std::string const &pattern, CacheSetHelper &helper) {
 		PackageContainer cont;
-		PackageContainerInterface::FromString(&cont, Cache, pattern, helper);
+		helper.PackageFrom(CacheSetHelper::PACKAGENAME, &cont, Cache, pattern);
 		return cont;
 	}
 	static PackageContainer FromString(pkgCacheFile &Cache, std::string const &pattern) {
@@ -318,7 +483,7 @@ public:									/*{{{*/
 	    \param helper responsible for error and message handling */
 	static PackageContainer FromCommandLine(pkgCacheFile &Cache, const char **cmdline, CacheSetHelper &helper) {
 		PackageContainer cont;
-		PackageContainerInterface::FromCommandLine(&cont, Cache, cmdline, helper);
+		helper.PackageFromCommandLine(&cont, Cache, cmdline);
 		return cont;
 	}
 	static PackageContainer FromCommandLine(pkgCacheFile &Cache, const char **cmdline) {
@@ -340,14 +505,14 @@ public:									/*{{{*/
 	static std::map<unsigned short, PackageContainer> GroupedFromCommandLine(
 										 pkgCacheFile &Cache,
 										 const char **cmdline,
-										 std::list<Modifier> const &mods,
+										 std::list<CacheSetHelper::PkgModifier> const &mods,
 										 unsigned short const &fallback,
 										 CacheSetHelper &helper) {
 		std::map<unsigned short, PackageContainer> pkgsets;
 		for (const char **I = cmdline; *I != 0; ++I) {
 			unsigned short modID = fallback;
 			PackageContainer pkgset;
-			PackageContainerInterface::FromModifierCommandLine(modID, &pkgset, Cache, *I, mods, helper);
+			helper.PackageFromModifierCommandLine(modID, &pkgset, Cache, *I, mods);
 			pkgsets[modID].insert(pkgset);
 		}
 		return pkgsets;
@@ -355,22 +520,23 @@ public:									/*{{{*/
 	static std::map<unsigned short, PackageContainer> GroupedFromCommandLine(
 										 pkgCacheFile &Cache,
 										 const char **cmdline,
-										 std::list<Modifier> const &mods,
+										 std::list<CacheSetHelper::PkgModifier> const &mods,
 										 unsigned short const &fallback) {
 		CacheSetHelper helper;
 		return GroupedFromCommandLine(Cache, cmdline,
 				mods, fallback, helper);
 	}
 									/*}}}*/
-private:								/*{{{*/
-	Constructor ConstructedBy;
-									/*}}}*/
 };									/*}}}*/
-
+// specialisations for push_back containers: std::list & std::vector	/*{{{*/
 template<> template<class Cont> void PackageContainer<std::list<pkgCache::PkgIterator> >::insert(PackageContainer<Cont> const &pkgcont) {
 	for (typename PackageContainer<Cont>::const_iterator p = pkgcont.begin(); p != pkgcont.end(); ++p)
 		_cont.push_back(*p);
 }
+template<> template<class Cont> void PackageContainer<std::vector<pkgCache::PkgIterator> >::insert(PackageContainer<Cont> const &pkgcont) {
+	for (typename PackageContainer<Cont>::const_iterator p = pkgcont.begin(); p != pkgcont.end(); ++p)
+		_cont.push_back(*p);
+}
 // these two are 'inline' as otherwise the linker has problems with seeing these untemplated
 // specializations again and again - but we need to see them, so that library users can use them
 template<> inline bool PackageContainer<std::list<pkgCache::PkgIterator> >::insert(pkgCache::PkgIterator const &P) {
@@ -379,12 +545,65 @@ template<> inline bool PackageContainer<std::list<pkgCache::PkgIterator> >::inse
 	_cont.push_back(P);
 	return true;
 }
+template<> inline bool PackageContainer<std::vector<pkgCache::PkgIterator> >::insert(pkgCache::PkgIterator const &P) {
+	if (P.end() == true)
+		return false;
+	_cont.push_back(P);
+	return true;
+}
 template<> inline void PackageContainer<std::list<pkgCache::PkgIterator> >::insert(const_iterator begin, const_iterator end) {
 	for (const_iterator p = begin; p != end; ++p)
 		_cont.push_back(*p);
 }
+template<> inline void PackageContainer<std::vector<pkgCache::PkgIterator> >::insert(const_iterator begin, const_iterator end) {
+	for (const_iterator p = begin; p != end; ++p)
+		_cont.push_back(*p);
+}
+									/*}}}*/
+
+template<> template<class Compare> inline bool PackageContainer<std::vector<pkgCache::PkgIterator> >::sort(Compare Comp) {
+	std::sort(_cont.begin(), _cont.end(), Comp);
+	return true;
+}
+
+// class PackageUniverse - pkgCache as PackageContainerInterface	/*{{{*/
+/** \class PackageUniverse
+
+    Wraps around our usual pkgCache, so that it can be stuffed into methods
+    expecting a PackageContainer.
+
+    The wrapping is read-only in practice modeled by making erase and co
+    private methods. */
+class APT_HIDDEN PackageUniverse : public PackageContainerInterface {
+	pkgCache * const _cont;
+public:
+	typedef pkgCache::PkgIterator iterator;
+	typedef pkgCache::PkgIterator const_iterator;
+
+	APT_PUBLIC bool empty() const { return false; }
+	APT_PUBLIC size_t size() const { return _cont->Head().PackageCount; }
+
+	APT_PUBLIC const_iterator begin() const { return _cont->PkgBegin(); }
+	APT_PUBLIC const_iterator end() const { return  _cont->PkgEnd(); }
+	APT_PUBLIC iterator begin() { return _cont->PkgBegin(); }
+	APT_PUBLIC iterator end() { return _cont->PkgEnd(); }
+
+	APT_PUBLIC PackageUniverse(pkgCache * const Owner) : _cont(Owner) { }
+
+private:
+	bool insert(pkgCache::PkgIterator const &) { return true; }
+	template<class Cont> void insert(PackageContainer<Cont> const &) { }
+	void insert(const_iterator, const_iterator) { }
+
+	void clear() { }
+	iterator& erase(iterator &iter) { return iter; }
+	size_t erase(const pkgCache::PkgIterator) { return 0; }
+	void erase(iterator, iterator) { }
+};
+									/*}}}*/
 typedef PackageContainer<std::set<pkgCache::PkgIterator> > PackageSet;
 typedef PackageContainer<std::list<pkgCache::PkgIterator> > PackageList;
+typedef PackageContainer<std::vector<pkgCache::PkgIterator> > PackageVector;
 
 class VersionContainerInterface {					/*{{{*/
 /** \class APT::VersionContainerInterface
@@ -426,45 +645,83 @@ public:
 	virtual void clear() = 0;
 
 	/** \brief specifies which version(s) will be returned if non is given */
-	enum Version {
-		/** All versions */
-		ALL,
-		/** Candidate and installed version */
-		CANDANDINST,
-		/** Candidate version */
-		CANDIDATE,
-		/** Installed version */
-		INSTALLED,
-		/** Candidate or if non installed version */
-		CANDINST,
-		/** Installed or if non candidate version */
-		INSTCAND,
-		/** Newest version */
-		NEWEST
+	enum APT_DEPRECATED Version {
+		ALL = CacheSetHelper::ALL,
+		CANDANDINST = CacheSetHelper::CANDANDINST,
+		CANDIDATE = CacheSetHelper::CANDIDATE,
+		INSTALLED = CacheSetHelper::INSTALLED,
+		CANDINST = CacheSetHelper::CANDINST,
+		INSTCAND = CacheSetHelper::INSTCAND,
+		NEWEST = CacheSetHelper::NEWEST
 	};
 
 	struct Modifier {
-		enum Position { NONE, PREFIX, POSTFIX };
-		unsigned short ID;
+		unsigned short const ID;
 		const char * const Alias;
-		Position Pos;
-		Version SelectVersion;
+		enum Position { NONE, PREFIX, POSTFIX } const Pos;
+		enum CacheSetHelper::VerSelector const SelectVersion;
 		Modifier (unsigned short const &id, const char * const alias, Position const &pos,
-			  Version const &select) : ID(id), Alias(alias), Pos(pos),
+			  enum CacheSetHelper::VerSelector const select) : ID(id), Alias(alias), Pos(pos),
 			 SelectVersion(select) {}
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic push
+	#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+		APT_DEPRECATED Modifier(unsigned short const &id, const char * const alias, Position const &pos,
+			  Version const &select) : ID(id), Alias(alias), Pos(pos),
+			 SelectVersion((CacheSetHelper::VerSelector)select) {}
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic pop
+#endif
 	};
 
 	static bool FromCommandLine(VersionContainerInterface * const vci, pkgCacheFile &Cache,
-				    const char **cmdline, Version const &fallback,
+				    const char **cmdline, CacheSetHelper::VerSelector const fallback,
 				    CacheSetHelper &helper);
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic push
+	#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+	APT_DEPRECATED static bool FromCommandLine(VersionContainerInterface * const vci, pkgCacheFile &Cache,
+				    const char **cmdline, Version const &fallback,
+				    CacheSetHelper &helper) {
+	   return FromCommandLine(vci, Cache, cmdline, (CacheSetHelper::VerSelector)fallback, helper);
+	}
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic pop
+#endif
 
 	static bool FromString(VersionContainerInterface * const vci, pkgCacheFile &Cache,
-			       std::string pkg, Version const &fallback, CacheSetHelper &helper,
+			       std::string pkg, CacheSetHelper::VerSelector const fallback, CacheSetHelper &helper,
 			       bool const onlyFromName = false);
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic push
+	#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+	APT_DEPRECATED static bool FromString(VersionContainerInterface * const vci, pkgCacheFile &Cache,
+			       std::string pkg, Version const &fallback, CacheSetHelper &helper,
+			       bool const onlyFromName = false) {
+	   return FromString(vci, Cache, pkg, (CacheSetHelper::VerSelector)fallback, helper, onlyFromName);
+	}
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic pop
+#endif
 
 	static bool FromPackage(VersionContainerInterface * const vci, pkgCacheFile &Cache,
-				pkgCache::PkgIterator const &P, Version const &fallback,
+				pkgCache::PkgIterator const &P, CacheSetHelper::VerSelector const fallback,
 				CacheSetHelper &helper);
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic push
+	#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+	APT_DEPRECATED static bool FromPackage(VersionContainerInterface * const vci, pkgCacheFile &Cache,
+				pkgCache::PkgIterator const &P, Version const &fallback,
+				CacheSetHelper &helper) {
+	   return FromPackage(vci, Cache, P, (CacheSetHelper::VerSelector)fallback, helper);
+	}
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic pop
+#endif
 
 	static bool FromModifierCommandLine(unsigned short &modID,
 					    VersionContainerInterface * const vci,
@@ -476,8 +733,22 @@ public:
 	static bool FromDependency(VersionContainerInterface * const vci,
 				   pkgCacheFile &Cache,
 				   pkgCache::DepIterator const &D,
-				   Version const &selector,
+				   CacheSetHelper::VerSelector const selector,
 				   CacheSetHelper &helper);
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic push
+	#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+	APT_DEPRECATED static bool FromDependency(VersionContainerInterface * const vci,
+				   pkgCacheFile &Cache,
+				   pkgCache::DepIterator const &D,
+				   Version const &selector,
+				   CacheSetHelper &helper) {
+	   return FromDependency(vci, Cache, D, (CacheSetHelper::VerSelector)selector, helper);
+	}
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic pop
+#endif
 
 protected:								/*{{{*/
 
@@ -559,6 +830,18 @@ public:									/*{{{*/
 	iterator end() { return iterator(_cont.end()); }
 	const_iterator find(pkgCache::VerIterator const &V) const { return const_iterator(_cont.find(V)); }
 
+	/** \brief sort all included versions with given comparer
+
+	    Some containers are sorted by default, some are not and can't be,
+	    but a few like std::vector can be sorted if need be, so this can be
+	    specialized in later on. The default is that this will fail though.
+	    Specifically, already sorted containers like std::set will return
+	    false as well as there is no easy way to check that the given comparer
+	    would sort in the same way the set is currently sorted
+
+	    \return \b true if the set was sorted, \b false if not. */
+	template<class Compare> bool sort(Compare /*Comp*/) { return false; }
+
 	/** \brief returns all versions specified on the commandline
 
 	    Get all versions from the commandline, uses given default version if
@@ -568,35 +851,64 @@ public:									/*{{{*/
 	    \param fallback version specification
 	    \param helper responsible for error and message handling */
 	static VersionContainer FromCommandLine(pkgCacheFile &Cache, const char **cmdline,
-			Version const &fallback, CacheSetHelper &helper) {
+			CacheSetHelper::VerSelector const fallback, CacheSetHelper &helper) {
 		VersionContainer vercon;
 		VersionContainerInterface::FromCommandLine(&vercon, Cache, cmdline, fallback, helper);
 		return vercon;
 	}
 	static VersionContainer FromCommandLine(pkgCacheFile &Cache, const char **cmdline,
-			Version const &fallback) {
+			CacheSetHelper::VerSelector const fallback) {
 		CacheSetHelper helper;
 		return FromCommandLine(Cache, cmdline, fallback, helper);
 	}
 	static VersionContainer FromCommandLine(pkgCacheFile &Cache, const char **cmdline) {
-		return FromCommandLine(Cache, cmdline, CANDINST);
+		return FromCommandLine(Cache, cmdline, CacheSetHelper::CANDINST);
 	}
-
 	static VersionContainer FromString(pkgCacheFile &Cache, std::string const &pkg,
-			Version const &fallback, CacheSetHelper &helper,
+			CacheSetHelper::VerSelector const fallback, CacheSetHelper &helper,
                                            bool const /*onlyFromName = false*/) {
 		VersionContainer vercon;
 		VersionContainerInterface::FromString(&vercon, Cache, pkg, fallback, helper);
 		return vercon;
 	}
 	static VersionContainer FromString(pkgCacheFile &Cache, std::string pkg,
-			Version const &fallback) {
+			CacheSetHelper::VerSelector const fallback) {
 		CacheSetHelper helper;
 		return FromString(Cache, pkg, fallback, helper);
 	}
 	static VersionContainer FromString(pkgCacheFile &Cache, std::string pkg) {
-		return FromString(Cache, pkg, CANDINST);
+		return FromString(Cache, pkg, CacheSetHelper::CANDINST);
+	}
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic push
+	#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+	static VersionContainer FromCommandLine(pkgCacheFile &Cache, const char **cmdline,
+			Version const &fallback, CacheSetHelper &helper) {
+		VersionContainer vercon;
+		VersionContainerInterface::FromCommandLine(&vercon, Cache, cmdline, (CacheSetHelper::VerSelector)fallback, helper);
+		return vercon;
+	}
+	static VersionContainer FromCommandLine(pkgCacheFile &Cache, const char **cmdline,
+			Version const &fallback) {
+		CacheSetHelper helper;
+		return FromCommandLine(Cache, cmdline, (CacheSetHelper::VerSelector)fallback, helper);
+	}
+	static VersionContainer FromString(pkgCacheFile &Cache, std::string const &pkg,
+			Version const &fallback, CacheSetHelper &helper,
+                                           bool const /*onlyFromName = false*/) {
+		VersionContainer vercon;
+		VersionContainerInterface::FromString(&vercon, Cache, pkg, (CacheSetHelper::VerSelector)fallback, helper);
+		return vercon;
 	}
+	static VersionContainer FromString(pkgCacheFile &Cache, std::string pkg,
+			Version const &fallback) {
+		CacheSetHelper helper;
+		return FromString(Cache, pkg, (CacheSetHelper::VerSelector)fallback, helper);
+	}
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic pop
+#endif
 
 	/** \brief returns all versions specified for the package
 
@@ -605,18 +917,36 @@ public:									/*{{{*/
 	    \param fallback the version(s) you want to get
 	    \param helper the helper used for display and error handling */
 	static VersionContainer FromPackage(pkgCacheFile &Cache, pkgCache::PkgIterator const &P,
-		Version const &fallback, CacheSetHelper &helper) {
+		CacheSetHelper::VerSelector const fallback, CacheSetHelper &helper) {
 		VersionContainer vercon;
 		VersionContainerInterface::FromPackage(&vercon, Cache, P, fallback, helper);
 		return vercon;
 	}
 	static VersionContainer FromPackage(pkgCacheFile &Cache, pkgCache::PkgIterator const &P,
-					    Version const &fallback) {
+					    CacheSetHelper::VerSelector const fallback) {
 		CacheSetHelper helper;
 		return FromPackage(Cache, P, fallback, helper);
 	}
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic push
+	#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+	static VersionContainer FromPackage(pkgCacheFile &Cache, pkgCache::PkgIterator const &P,
+		Version const &fallback, CacheSetHelper &helper) {
+		VersionContainer vercon;
+		VersionContainerInterface::FromPackage(&vercon, Cache, P, (CacheSetHelper::VerSelector)fallback, helper);
+		return vercon;
+	}
+	static VersionContainer FromPackage(pkgCacheFile &Cache, pkgCache::PkgIterator const &P,
+					    Version const &fallback) {
+		CacheSetHelper helper;
+		return FromPackage(Cache, P, (CacheSetHelper::VerSelector)fallback, helper);
+	}
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic pop
+#endif
 	static VersionContainer FromPackage(pkgCacheFile &Cache, pkgCache::PkgIterator const &P) {
-		return FromPackage(Cache, P, CANDIDATE);
+		return FromPackage(Cache, P, CacheSetHelper::CANDIDATE);
 	}
 
 	static std::map<unsigned short, VersionContainer> GroupedFromCommandLine(
@@ -645,26 +975,48 @@ public:									/*{{{*/
 	}
 
 	static VersionContainer FromDependency(pkgCacheFile &Cache, pkgCache::DepIterator const &D,
-					       Version const &selector, CacheSetHelper &helper) {
+					       CacheSetHelper::VerSelector const selector, CacheSetHelper &helper) {
 		VersionContainer vercon;
 		VersionContainerInterface::FromDependency(&vercon, Cache, D, selector, helper);
 		return vercon;
 	}
 	static VersionContainer FromDependency(pkgCacheFile &Cache, pkgCache::DepIterator const &D,
-					       Version const &selector) {
+					       CacheSetHelper::VerSelector const selector) {
 		CacheSetHelper helper;
 		return FromPackage(Cache, D, selector, helper);
 	}
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic push
+	#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+	static VersionContainer FromDependency(pkgCacheFile &Cache, pkgCache::DepIterator const &D,
+					       Version const &selector, CacheSetHelper &helper) {
+		VersionContainer vercon;
+		VersionContainerInterface::FromDependency(&vercon, Cache, D, (CacheSetHelper::VerSelector)selector, helper);
+		return vercon;
+	}
+	static VersionContainer FromDependency(pkgCacheFile &Cache, pkgCache::DepIterator const &D,
+					       Version const &selector) {
+		CacheSetHelper helper;
+		return FromPackage(Cache, D, (CacheSetHelper::VerSelector)selector, helper);
+	}
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic pop
+#endif
 	static VersionContainer FromDependency(pkgCacheFile &Cache, pkgCache::DepIterator const &D) {
-		return FromPackage(Cache, D, CANDIDATE);
+		return FromPackage(Cache, D, CacheSetHelper::CANDIDATE);
 	}
 									/*}}}*/
 };									/*}}}*/
-
+// specialisations for push_back containers: std::list & std::vector	/*{{{*/
 template<> template<class Cont> void VersionContainer<std::list<pkgCache::VerIterator> >::insert(VersionContainer<Cont> const &vercont) {
 	for (typename VersionContainer<Cont>::const_iterator v = vercont.begin(); v != vercont.end(); ++v)
 		_cont.push_back(*v);
 }
+template<> template<class Cont> void VersionContainer<std::vector<pkgCache::VerIterator> >::insert(VersionContainer<Cont> const &vercont) {
+	for (typename VersionContainer<Cont>::const_iterator v = vercont.begin(); v != vercont.end(); ++v)
+		_cont.push_back(*v);
+}
 // these two are 'inline' as otherwise the linker has problems with seeing these untemplated
 // specializations again and again - but we need to see them, so that library users can use them
 template<> inline bool VersionContainer<std::list<pkgCache::VerIterator> >::insert(pkgCache::VerIterator const &V) {
@@ -673,11 +1025,29 @@ template<> inline bool VersionContainer<std::list<pkgCache::VerIterator> >::inse
 	_cont.push_back(V);
 	return true;
 }
+template<> inline bool VersionContainer<std::vector<pkgCache::VerIterator> >::insert(pkgCache::VerIterator const &V) {
+	if (V.end() == true)
+		return false;
+	_cont.push_back(V);
+	return true;
+}
 template<> inline void VersionContainer<std::list<pkgCache::VerIterator> >::insert(const_iterator begin, const_iterator end) {
 	for (const_iterator v = begin; v != end; ++v)
 		_cont.push_back(*v);
 }
+template<> inline void VersionContainer<std::vector<pkgCache::VerIterator> >::insert(const_iterator begin, const_iterator end) {
+	for (const_iterator v = begin; v != end; ++v)
+		_cont.push_back(*v);
+}
+									/*}}}*/
+
+template<> template<class Compare> inline bool VersionContainer<std::vector<pkgCache::VerIterator> >::sort(Compare Comp) {
+	std::sort(_cont.begin(), _cont.end(), Comp);
+	return true;
+}
+
 typedef VersionContainer<std::set<pkgCache::VerIterator> > VersionSet;
 typedef VersionContainer<std::list<pkgCache::VerIterator> > VersionList;
+typedef VersionContainer<std::vector<pkgCache::VerIterator> > VersionVector;
 }
 #endif

+ 7 - 3
apt-pkg/cdrom.cc

@@ -913,10 +913,14 @@ bool pkgCdrom::Add(pkgCdromStatus *log)					/*{{{*/
    return true;
 }
 									/*}}}*/
-pkgUdevCdromDevices::pkgUdevCdromDevices()                     		/*{{{*/
-   : libudev_handle(NULL)
+pkgUdevCdromDevices::pkgUdevCdromDevices()				/*{{{*/
+: libudev_handle(NULL), udev_new(NULL), udev_enumerate_add_match_property(NULL),
+   udev_enumerate_scan_devices(NULL), udev_enumerate_get_list_entry(NULL),
+   udev_device_new_from_syspath(NULL), udev_enumerate_get_udev(NULL),
+   udev_list_entry_get_name(NULL), udev_device_get_devnode(NULL),
+   udev_enumerate_new(NULL), udev_list_entry_get_next(NULL),
+   udev_device_get_property_value(NULL), udev_enumerate_add_match_sysattr(NULL)
 {
-
 }
 									/*}}}*/
 

+ 4 - 1
apt-pkg/clean.cc

@@ -34,7 +34,10 @@
 bool pkgArchiveCleaner::Go(std::string Dir,pkgCache &Cache)
 {
    bool CleanInstalled = _config->FindB("APT::Clean-Installed",true);
-      
+
+   if(Dir == "/")
+      return _error->Error(_("Clean of %s is not supported"), Dir.c_str());
+
    DIR *D = opendir(Dir.c_str());
    if (D == 0)
       return _error->Errno("opendir",_("Unable to read %s"),Dir.c_str());

+ 11 - 8
apt-pkg/contrib/cmndline.cc

@@ -47,23 +47,26 @@ CommandLine::~CommandLine()
 char const * CommandLine::GetCommand(Dispatch const * const Map,
       unsigned int const argc, char const * const * const argv)
 {
-   // if there is a -- on the line there must be the word we search for around it
-   // as -- marks the end of the options, just not sure if the command can be
-   // considered an option or not, so accept both
+   // if there is a -- on the line there must be the word we search for either
+   // before it (as -- marks the end of the options) or right after it (as we can't
+   // decide if the command is actually an option, given that in theory, you could
+   // have parameters named like commands)
    for (size_t i = 1; i < argc; ++i)
    {
       if (strcmp(argv[i], "--") != 0)
 	 continue;
-      ++i;
-      if (i < argc)
+      // check if command is before --
+      for (size_t k = 1; k < i; ++k)
 	 for (size_t j = 0; Map[j].Match != NULL; ++j)
-	    if (strcmp(argv[i], Map[j].Match) == 0)
+	    if (strcmp(argv[k], Map[j].Match) == 0)
 	       return Map[j].Match;
-      i -= 2;
-      if (i != 0)
+      // see if the next token after -- is the command
+      ++i;
+      if (i < argc)
 	 for (size_t j = 0; Map[j].Match != NULL; ++j)
 	    if (strcmp(argv[i], Map[j].Match) == 0)
 	       return Map[j].Match;
+      // we found a --, but not a command
       return NULL;
    }
    // no --, so search for the first word matching a command

+ 0 - 5
apt-pkg/contrib/configuration.cc

@@ -253,11 +253,6 @@ string Configuration::FindDir(const char *Name,const char *Default) const
 // Configuration::FindVector - Find a vector of values			/*{{{*/
 // ---------------------------------------------------------------------
 /* Returns a vector of config values under the given item */
-#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR < 13)
-vector<string> Configuration::FindVector(const char *Name) const { 
-   return FindVector(Name, ""); 
-}
-#endif
 vector<string> Configuration::FindVector(const char *Name, std::string const &Default) const
 {
    vector<string> Vec;

+ 6 - 8
apt-pkg/contrib/configuration.h

@@ -34,6 +34,8 @@
 #include <vector>
 #include <iostream>
 
+#include <apt-pkg/macros.h>
+
 #ifndef APT_8_CLEANER_HEADERS
 using std::string;
 #endif
@@ -59,7 +61,7 @@ class Configuration
    
    Item *Root;
    bool ToFree;
-   
+
    Item *Lookup(Item *Head,const char *S,unsigned long const &Len,bool const &Create);
    Item *Lookup(const char *Name,const bool &Create);
    inline const Item *Lookup(const char *Name) const
@@ -82,12 +84,8 @@ class Configuration
     *
     * \param Name of the parent node
     * \param Default list of values separated by commas */
-   std::vector<std::string> FindVector(const char *Name, std::string const &Default) const;
-   std::vector<std::string> FindVector(std::string const &Name, std::string const &Default) const { return FindVector(Name.c_str(), Default); };
-#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR < 13)
-   std::vector<std::string> FindVector(const char *Name) const;
-#endif
-   std::vector<std::string> FindVector(std::string const &Name="") const { return FindVector(Name.c_str(), ""); };
+   std::vector<std::string> FindVector(const char *Name, std::string const &Default = "") const;
+   std::vector<std::string> FindVector(std::string const &Name, std::string const &Default = "") const { return FindVector(Name.c_str(), Default); };
    int FindI(const char *Name,int const &Default = 0) const;
    int FindI(std::string const &Name,int const &Default = 0) const {return FindI(Name.c_str(),Default);};
    bool FindB(const char *Name,bool const &Default = false) const;
@@ -127,7 +125,7 @@ class Configuration
    class MatchAgainstConfig
    {
      std::vector<regex_t *> patterns;
-     void clearPatterns();
+     APT_HIDDEN void clearPatterns();
 
    public:
      MatchAgainstConfig(char const * Config);

+ 101 - 6
apt-pkg/contrib/fileutl.cc

@@ -47,6 +47,8 @@
 #include <signal.h>
 #include <errno.h>
 #include <glob.h>
+#include <pwd.h>
+#include <grp.h>
 
 #include <set>
 #include <algorithm>
@@ -63,6 +65,10 @@
 #include <endian.h>
 #include <stdint.h>
 
+#if __gnu_linux__
+#include <sys/prctl.h>
+#endif
+
 #include <apti18n.h>
 									/*}}}*/
 
@@ -890,7 +896,7 @@ class FileFdPrivate {							/*{{{*/
 	   bool eof;
 	   bool compressing;
 
-	   LZMAFILE() : file(NULL), eof(false), compressing(false) {}
+	   LZMAFILE() : file(NULL), eof(false), compressing(false) { buffer[0] = '\0'; }
 	   ~LZMAFILE() {
 	      if (compressing == true)
 	      {
@@ -1278,7 +1284,8 @@ bool FileFd::OpenInternDescriptor(unsigned int const Mode, APT::Configuration::C
 	 if (d->lzma == NULL)
 	    d->lzma = new FileFdPrivate::LZMAFILE;
 	 d->lzma->file = (FILE*) compress_struct;
-	 d->lzma->stream = LZMA_STREAM_INIT;
+         lzma_stream tmp_stream = LZMA_STREAM_INIT;
+	 d->lzma->stream = tmp_stream;
 
 	 if ((Mode & ReadWrite) == ReadWrite)
 	    return FileFdError("ReadWrite mode is not supported for file %s", FileName.c_str());
@@ -1834,7 +1841,8 @@ static bool StatFileFd(char const * const msg, int const iFd, std::string const
 	 // higher-level code will generate more meaningful messages,
 	 // even translated this would be meaningless for users
 	 return _error->Errno("fstat", "Unable to determine %s for fd %i", msg, iFd);
-      ispipe = S_ISFIFO(Buf.st_mode);
+      if (FileName.empty() == false)
+	 ispipe = S_ISFIFO(Buf.st_mode);
    }
 
    // for compressor pipes st_size is undefined and at 'best' zero
@@ -2118,10 +2126,8 @@ bool Popen(const char* Args[], FileFd &Fd, pid_t &Child, FileFd::OpenMode Mode)
 
    int Pipe[2] = {-1, -1};
    if(pipe(Pipe) != 0)
-   {
       return _error->Errno("pipe", _("Failed to create subprocess IPC"));
-      return NULL;
-   }
+
    std::set<int> keep_fds;
    keep_fds.insert(Pipe[0]);
    keep_fds.insert(Pipe[1]);
@@ -2164,3 +2170,92 @@ bool Popen(const char* Args[], FileFd &Fd, pid_t &Child, FileFd::OpenMode Mode)
 
    return true;
 }
+
+bool DropPrivs()
+{
+   // uid will be 0 in the end, but gid might be different anyway
+   uid_t old_uid = getuid();
+   gid_t old_gid = getgid();
+
+   if (old_uid != 0)
+      return true;
+   if(_config->FindB("Debug::NoDropPrivs", false) == true)
+      return true;
+
+   const std::string toUser = _config->Find("APT::Sandbox::User", "_apt");
+   struct passwd *pw = getpwnam(toUser.c_str());
+   if (pw == NULL)
+      return _error->Error("No user %s, can not drop rights", toUser.c_str());
+
+#if __gnu_linux__
+   // see prctl(2), needs linux3.5
+   int ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0,0, 0);
+   if(ret < 0)
+      _error->Warning("PR_SET_NO_NEW_PRIVS failed with %i", ret);
+#endif
+   // Do not change the order here, it might break things
+   if (setgroups(1, &pw->pw_gid))
+      return _error->Errno("setgroups", "Failed to setgroups");
+
+   if (setegid(pw->pw_gid) != 0)
+      return _error->Errno("setegid", "Failed to setegid");
+
+   if (setgid(pw->pw_gid) != 0)
+      return _error->Errno("setgid", "Failed to setgid");
+
+   if (setuid(pw->pw_uid) != 0)
+      return _error->Errno("setuid", "Failed to setuid");
+
+   // the seteuid() is probably uneeded (at least thats what the linux
+   // man-page says about setuid(2)) but we cargo culted it anyway
+   if (seteuid(pw->pw_uid) != 0)
+      return _error->Errno("seteuid", "Failed to seteuid");
+
+   // Verify that the user has only a single group, and the correct one
+   gid_t groups[1];
+   if (getgroups(1, groups) != 1)
+      return _error->Errno("getgroups", "Could not get new groups");
+   if (groups[0] != pw->pw_gid)
+      return _error->Error("Could not switch group");
+
+   // Verify that gid, egid, uid, and euid changed
+   if (getgid() != pw->pw_gid)
+      return _error->Error("Could not switch group");
+   if (getegid() != pw->pw_gid)
+      return _error->Error("Could not switch effective group");
+   if (getuid() != pw->pw_uid)
+      return _error->Error("Could not switch user");
+   if (geteuid() != pw->pw_uid)
+      return _error->Error("Could not switch effective user");
+
+#ifdef HAVE_GETRESUID
+   // verify that the saved set-user-id was changed as well
+   uid_t ruid = 0;
+   uid_t euid = 0;
+   uid_t suid = 0;
+   if (getresuid(&ruid, &euid, &suid))
+      return _error->Errno("getresuid", "Could not get saved set-user-ID");
+   if (suid != pw->pw_uid)
+      return _error->Error("Could not switch saved set-user-ID");
+#endif
+
+#ifdef HAVE_GETRESGID
+   // verify that the saved set-group-id was changed as well
+   gid_t rgid = 0;
+   gid_t egid = 0;
+   gid_t sgid = 0;
+   if (getresgid(&rgid, &egid, &sgid))
+      return _error->Errno("getresuid", "Could not get saved set-group-ID");
+   if (sgid != pw->pw_gid)
+      return _error->Error("Could not switch saved set-group-ID");
+#endif
+
+   // Check that uid and gid changes do not work anymore
+   if (pw->pw_gid != old_gid && (setgid(old_gid) != -1 || setegid(old_gid) != -1))
+      return _error->Error("Could restore a gid to root, privilege dropping did not work");
+
+   if (pw->pw_uid != old_uid && (setuid(old_uid) != -1 || seteuid(old_uid) != -1))
+      return _error->Error("Could restore a uid to root, privilege dropping did not work");
+
+   return true;
+}

+ 16 - 0
apt-pkg/contrib/fileutl.h

@@ -85,7 +85,9 @@ class FileFd
    bool Skip(unsigned long long To);
    bool Truncate(unsigned long long To);
    unsigned long long Tell();
+   // the size of the file content (compressed files will be uncompressed first)
    unsigned long long Size();
+   // the size of the file itself
    unsigned long long FileSize();
    time_t ModificationTime();
 
@@ -193,9 +195,23 @@ pid_t ExecFork(std::set<int> keep_fds);
 void MergeKeepFdsFromConfiguration(std::set<int> &keep_fds);
 bool ExecWait(pid_t Pid,const char *Name,bool Reap = false);
 
+
 // check if the given file starts with a PGP cleartext signature
 bool StartsWithGPGClearTextSignature(std::string const &FileName);
 
+/**
+ * \brief Drop privileges
+ *
+ * Drop the privileges to the user _apt (or the one specified in
+ * APT::Sandbox::User). This does not set the supplementary group
+ * ids up correctly, it only uses the default group. Also prevent
+ * the process from gaining any new privileges afterwards, at least
+ * on Linux.
+ *
+ * \return true on success, false on failure with _error set
+ */
+bool DropPrivs();
+
 // File string manipulators
 std::string flNotDir(std::string File);
 std::string flNotFile(std::string File);

+ 18 - 45
apt-pkg/contrib/gpgv.cc

@@ -32,50 +32,30 @@ static char * GenerateTemporaryFileTemplate(const char *basename)	/*{{{*/
 									/*}}}*/
 // ExecGPGV - returns the command needed for verify			/*{{{*/
 // ---------------------------------------------------------------------
-/* Generating the commandline for calling gpgv is somehow complicated as
+/* Generating the commandline for calling gpg is somehow complicated as
    we need to add multiple keyrings and user supplied options.
-   Also, as gpgv has no options to enforce a certain reduced style of
+   Also, as gpg has no options to enforce a certain reduced style of
    clear-signed files (=the complete content of the file is signed and
    the content isn't encoded) we do a divide and conquer approach here
-   and split up the clear-signed file in message and signature for gpgv
+   and split up the clear-signed file in message and signature for gpg.
+   And as a cherry on the cake, we use our apt-key wrapper to do part
+   of the lifting in regards to merging keyrings. Fun for the whole family.
 */
 void ExecGPGV(std::string const &File, std::string const &FileGPG,
              int const &statusfd, int fd[2])
 {
    #define EINTERNAL 111
-   std::string const gpgvpath = _config->Find("Dir::Bin::gpg", "/usr/bin/gpgv");
-   // FIXME: remove support for deprecated APT::GPGV setting
-   std::string const trustedFile = _config->Find("APT::GPGV::TrustedKeyring", _config->FindFile("Dir::Etc::Trusted"));
-   std::string const trustedPath = _config->FindDir("Dir::Etc::TrustedParts");
+   std::string const aptkey = _config->FindFile("Dir::Bin::apt-key", "/usr/bin/apt-key");
 
    bool const Debug = _config->FindB("Debug::Acquire::gpgv", false);
 
-   if (Debug == true)
-   {
-      std::clog << "gpgv path: " << gpgvpath << std::endl;
-      std::clog << "Keyring file: " << trustedFile << std::endl;
-      std::clog << "Keyring path: " << trustedPath << std::endl;
-   }
-
-   std::vector<std::string> keyrings;
-   if (DirectoryExists(trustedPath))
-     keyrings = GetListOfFilesInDir(trustedPath, "gpg", false, true);
-   if (RealFileExists(trustedFile) == true)
-     keyrings.push_back(trustedFile);
-
    std::vector<const char *> Args;
-   Args.reserve(30);
-
-   if (keyrings.empty() == true)
-   {
-      // TRANSLATOR: %s is the trusted keyring parts directory
-      ioprintf(std::cerr, _("No keyring installed in %s."),
-	    _config->FindDir("Dir::Etc::TrustedParts").c_str());
-      exit(EINTERNAL);
-   }
+   Args.reserve(10);
 
-   Args.push_back(gpgvpath.c_str());
-   Args.push_back("--ignore-time-conflict");
+   Args.push_back(aptkey.c_str());
+   Args.push_back("--quiet");
+   Args.push_back("--readonly");
+   Args.push_back("verify");
 
    char statusfdstr[10];
    if (statusfd != -1)
@@ -85,13 +65,6 @@ void ExecGPGV(std::string const &File, std::string const &FileGPG,
       Args.push_back(statusfdstr);
    }
 
-   for (std::vector<std::string>::const_iterator K = keyrings.begin();
-	K != keyrings.end(); ++K)
-   {
-      Args.push_back("--keyring");
-      Args.push_back(K->c_str());
-   }
-
    Configuration::Item const *Opts;
    Opts = _config->Tree("Acquire::gpgv::Options");
    if (Opts != 0)
@@ -160,7 +133,7 @@ void ExecGPGV(std::string const &File, std::string const &FileGPG,
 
    if (Debug == true)
    {
-      std::clog << "Preparing to exec: " << gpgvpath;
+      std::clog << "Preparing to exec: ";
       for (std::vector<const char *>::const_iterator a = Args.begin(); *a != NULL; ++a)
 	 std::clog << " " << *a;
       std::clog << std::endl;
@@ -168,7 +141,7 @@ void ExecGPGV(std::string const &File, std::string const &FileGPG,
 
    if (statusfd != -1)
    {
-      int const nullfd = open("/dev/null", O_RDONLY);
+      int const nullfd = open("/dev/null", O_WRONLY);
       close(fd[0]);
       // Redirect output to /dev/null; we read from the status fd
       if (statusfd != STDOUT_FILENO)
@@ -185,7 +158,7 @@ void ExecGPGV(std::string const &File, std::string const &FileGPG,
 
    if (releaseSignature == DETACHED)
    {
-      execvp(gpgvpath.c_str(), (char **) &Args[0]);
+      execvp(Args[0], (char **) &Args[0]);
       ioprintf(std::cerr, "Couldn't execute %s to check %s", Args[0], File.c_str());
       exit(EINTERNAL);
    }
@@ -205,7 +178,7 @@ void ExecGPGV(std::string const &File, std::string const &FileGPG,
       {
 	 if (statusfd != -1)
 	    dup2(fd[1], statusfd);
-	 execvp(gpgvpath.c_str(), (char **) &Args[0]);
+	 execvp(Args[0], (char **) &Args[0]);
 	 ioprintf(std::cerr, "Couldn't execute %s to check %s", Args[0], File.c_str());
 	 UNLINK_EXIT(EINTERNAL);
       }
@@ -216,7 +189,7 @@ void ExecGPGV(std::string const &File, std::string const &FileGPG,
       {
 	 if (errno == EINTR)
 	    continue;
-	 ioprintf(std::cerr, _("Waited for %s but it wasn't there"), "gpgv");
+	 ioprintf(std::cerr, _("Waited for %s but it wasn't there"), "apt-key");
 	 UNLINK_EXIT(EINTERNAL);
       }
 #undef UNLINK_EXIT
@@ -229,14 +202,14 @@ void ExecGPGV(std::string const &File, std::string const &FileGPG,
       // check if it exit'ed normally …
       if (WIFEXITED(Status) == false)
       {
-	 ioprintf(std::cerr, _("Sub-process %s exited unexpectedly"), "gpgv");
+	 ioprintf(std::cerr, _("Sub-process %s exited unexpectedly"), "apt-key");
 	 exit(EINTERNAL);
       }
 
       // … and with a good exit code
       if (WEXITSTATUS(Status) != 0)
       {
-	 ioprintf(std::cerr, _("Sub-process %s returned an error code (%u)"), "gpgv", WEXITSTATUS(Status));
+	 ioprintf(std::cerr, _("Sub-process %s returned an error code (%u)"), "apt-key", WEXITSTATUS(Status));
 	 exit(WEXITSTATUS(Status));
       }
 

+ 2 - 2
apt-pkg/contrib/hashes.cc

@@ -209,11 +209,11 @@ bool HashStringList::operator==(HashStringList const &other) const	/*{{{*/
    std::string const forcedType = _config->Find("Acquire::ForceHash", "");
    if (forcedType.empty() == false)
    {
-      HashString const * const hs = other.find(forcedType);
+      HashString const * const hs = find(forcedType);
       HashString const * const ohs = other.find(forcedType);
       if (hs == NULL || ohs == NULL)
 	 return false;
-      return hs == ohs;
+      return *hs == *ohs;
    }
    short matches = 0;
    for (const_iterator hs = begin(); hs != end(); ++hs)

+ 1 - 1
apt-pkg/contrib/macros.h

@@ -138,7 +138,7 @@
 // Non-ABI-Breaks should only increase RELEASE number.
 // See also buildlib/libversion.mak
 #define APT_PKG_MAJOR 4
-#define APT_PKG_MINOR 13
+#define APT_PKG_MINOR 14
 #define APT_PKG_RELEASE 0
 
 #endif

+ 86 - 0
apt-pkg/contrib/proxy.cc

@@ -0,0 +1,86 @@
+// -*- mode: cpp; mode: fold -*-
+// Description								/*{{{*/
+/* ######################################################################
+   
+   Proxy - Proxy releated functions
+   
+   ##################################################################### */
+									/*}}}*/
+// Include Files							/*{{{*/
+#include<apt-pkg/configuration.h>
+#include<apt-pkg/error.h>
+#include<apt-pkg/fileutl.h>
+#include<apt-pkg/strutl.h>
+
+#include<iostream>
+#include <unistd.h>
+
+#include "proxy.h"
+
+
+// AutoDetectProxy - auto detect proxy          			/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool AutoDetectProxy(URI &URL)
+{
+   // we support both http/https debug options
+   bool Debug = _config->FindB("Debug::Acquire::"+URL.Access,false);
+
+   // the user already explicitly set a proxy for this host
+   if(_config->Find("Acquire::"+URL.Access+"::proxy::"+URL.Host, "") != "")
+      return true;
+
+   // option is "Acquire::http::Proxy-Auto-Detect" but we allow the old
+   // name without the dash ("-")
+   std::string AutoDetectProxyCmd = _config->Find("Acquire::"+URL.Access+"::Proxy-Auto-Detect",
+                                      _config->Find("Acquire::"+URL.Access+"::ProxyAutoDetect"));
+
+   if (AutoDetectProxyCmd.empty())
+      return true;
+
+   if (Debug)
+      std::clog << "Using auto proxy detect command: " << AutoDetectProxyCmd << std::endl;
+
+   int Pipes[2] = {-1,-1};
+   if (pipe(Pipes) != 0)
+      return _error->Errno("pipe", "Failed to create Pipe");
+
+   pid_t Process = ExecFork();
+   if (Process == 0)
+   {
+      close(Pipes[0]);
+      dup2(Pipes[1],STDOUT_FILENO);
+      SetCloseExec(STDOUT_FILENO,false);
+
+      std::string foo = URL;
+      const char *Args[4];
+      Args[0] = AutoDetectProxyCmd.c_str();
+      Args[1] = foo.c_str();
+      Args[2] = 0;
+      execv(Args[0],(char **)Args);
+      std::cerr << "Failed to exec method " << Args[0] << std::endl;
+      _exit(100);
+   }
+   char buf[512];
+   int InFd = Pipes[0];
+   close(Pipes[1]);
+   int res = read(InFd, buf, sizeof(buf)-1);
+   ExecWait(Process, "ProxyAutoDetect", true);
+
+   if (res < 0)
+      return _error->Errno("read", "Failed to read");
+   if (res == 0)
+      return _error->Warning("ProxyAutoDetect returned no data");
+
+   // add trailing \0
+   buf[res] = 0;
+
+   if (Debug)
+      std::clog << "auto detect command returned: '" << buf << "'" << std::endl;
+
+   if (strstr(buf, URL.Access.c_str()) == buf)
+      _config->Set("Acquire::"+URL.Access+"::proxy::"+URL.Host, _strstrip(buf));
+
+   return true;
+}
+									/*}}}*/

+ 16 - 0
apt-pkg/contrib/proxy.h

@@ -0,0 +1,16 @@
+// -*- mode: cpp; mode: fold -*-
+// Description								/*{{{*/
+/* ######################################################################
+   
+   Proxy - Proxy operations
+   
+   ##################################################################### */
+									/*}}}*/
+#ifndef PKGLIB_PROXY_H
+#define PKGLIB_PROXY_H
+
+class URI;
+bool AutoDetectProxy(URI &URL);
+
+
+#endif

+ 63 - 17
apt-pkg/contrib/strutl.cc

@@ -45,14 +45,26 @@ using namespace std;
 // ---------------------------------------------------------------------
 namespace APT {
    namespace String {
-std::string Strip(const std::string &s)
+std::string Strip(const std::string &str)
 {
-   size_t start = s.find_first_not_of(" \t\n");
-   // only whitespace
-   if (start == string::npos)
+   // ensure we have at least one character
+   if (str.empty() == true)
+      return str;
+
+   char const * const s = str.c_str();
+   size_t start = 0;
+   for (; isspace(s[start]) != 0; ++start)
+      ; // find the first not-space
+
+   // string contains only whitespaces
+   if (s[start] == '\0')
       return "";
-   size_t end = s.find_last_not_of(" \t\n");
-   return s.substr(start, end-start+1);
+
+   size_t end = str.length() - 1;
+   for (; isspace(s[end]) != 0; --end)
+      ; // find the last not-space
+
+   return str.substr(start, end - start + 1);
 }
 
 bool Endswith(const std::string &s, const std::string &end)
@@ -62,6 +74,13 @@ bool Endswith(const std::string &s, const std::string &end)
    return (s.substr(s.size() - end.size(), s.size()) == end);
 }
 
+bool Startswith(const std::string &s, const std::string &start)
+{
+   if (start.size() > s.size())
+      return false;
+   return (s.substr(0, start.size()) == start);
+}
+
 }
 }
 									/*}}}*/
@@ -434,23 +453,30 @@ string TimeToStr(unsigned long Sec)
 /* This replaces all occurrences of Subst with Contents in Str. */
 string SubstVar(const string &Str,const string &Subst,const string &Contents)
 {
+   if (Subst.empty() == true)
+      return Str;
+
    string::size_type Pos = 0;
    string::size_type OldPos = 0;
    string Temp;
-   
-   while (OldPos < Str.length() && 
+
+   while (OldPos < Str.length() &&
 	  (Pos = Str.find(Subst,OldPos)) != string::npos)
    {
-      Temp += string(Str,OldPos,Pos) + Contents;
-      OldPos = Pos + Subst.length();      
+      if (OldPos != Pos)
+	 Temp.append(Str, OldPos, Pos - OldPos);
+      if (Contents.empty() == false)
+	 Temp.append(Contents);
+      OldPos = Pos + Subst.length();
    }
-   
+
    if (OldPos == 0)
       return Str;
-   
+
+   if (OldPos >= Str.length())
+      return Temp;
    return Temp + string(Str,OldPos);
 }
-
 string SubstVar(string Str,const struct SubstVar *Vars)
 {
    for (; Vars->Subst != 0; Vars++)
@@ -697,9 +723,12 @@ string LookupTag(const string &Message,const char *Tag,const char *Default)
    then returns the result. Several varients on true/false are checked. */
 int StringToBool(const string &Text,int Default)
 {
-   char *End;
-   int Res = strtol(Text.c_str(),&End,0);   
-   if (End != Text.c_str() && Res >= 0 && Res <= 1)
+   char *ParseEnd;
+   int Res = strtol(Text.c_str(),&ParseEnd,0);
+   // ensure that the entire string was converted by strtol to avoid
+   // failures on "apt-cache show -a 0ad" where the "0" is converted
+   const char *TextEnd = Text.c_str()+Text.size();
+   if (ParseEnd == TextEnd && Res >= 0 && Res <= 1)
       return Res;
    
    // Check for positives
@@ -1039,7 +1068,7 @@ bool StrToNum(const char *Str,unsigned long long &Res,unsigned Len,unsigned Base
 // ---------------------------------------------------------------------
 /* This is used in decoding the 256bit encoded fixed length fields in
    tar files */
-bool Base256ToNum(const char *Str,unsigned long &Res,unsigned int Len)
+bool Base256ToNum(const char *Str,unsigned long long &Res,unsigned int Len)
 {
    if ((Str[0] & 0x80) == 0)
       return false;
@@ -1052,6 +1081,23 @@ bool Base256ToNum(const char *Str,unsigned long &Res,unsigned int Len)
    }
 }
 									/*}}}*/
+// Base256ToNum - Convert a fixed length binary to a number             /*{{{*/
+// ---------------------------------------------------------------------
+/* This is used in decoding the 256bit encoded fixed length fields in
+   tar files */
+bool Base256ToNum(const char *Str,unsigned long &Res,unsigned int Len)
+{
+   unsigned long long Num;
+   bool rc;
+
+   rc = Base256ToNum(Str, Num, Len);
+   Res = Num;
+   if (Res != Num)
+      return false;
+
+   return rc;
+}
+									/*}}}*/
 // HexDigit - Convert a hex character into an integer			/*{{{*/
 // ---------------------------------------------------------------------
 /* Helper for Hex2Num */

+ 4 - 2
apt-pkg/contrib/strutl.h

@@ -40,6 +40,7 @@ namespace APT {
    namespace String {
       std::string Strip(const std::string &s);
       bool Endswith(const std::string &s, const std::string &ending);
+      bool Startswith(const std::string &s, const std::string &starting);
    }
 }
 
@@ -72,6 +73,7 @@ bool ReadMessages(int Fd, std::vector<std::string> &List);
 bool StrToNum(const char *Str,unsigned long &Res,unsigned Len,unsigned Base = 0);
 bool StrToNum(const char *Str,unsigned long long &Res,unsigned Len,unsigned Base = 0);
 bool Base256ToNum(const char *Str,unsigned long &Res,unsigned int Len);
+bool Base256ToNum(const char *Str,unsigned long long &Res,unsigned int Len);
 bool Hex2Num(const std::string &Str,unsigned char *Num,unsigned int Length);
 
 // input changing string split
@@ -151,9 +153,9 @@ inline const char *DeNull(const char *s) {return (s == 0?"(null)":s);}
 class URI
 {
    void CopyFrom(const std::string &From);
-		 
+
    public:
-   
+
    std::string Access;
    std::string User;
    std::string Password;

+ 61 - 35
apt-pkg/deb/debindexfile.cc

@@ -81,14 +81,18 @@ pkgSrcRecords::Parser *debSourcesIndex::CreateSrcParser() const
 {
    string SourcesURI = _config->FindDir("Dir::State::lists") + 
       URItoFileName(IndexURI("Sources"));
-   string SourcesURIgzip = SourcesURI + ".gz";
 
-   if (!FileExists(SourcesURI) && !FileExists(SourcesURIgzip))
-      return NULL;
-   else if (!FileExists(SourcesURI) && FileExists(SourcesURIgzip))
-      SourcesURI = SourcesURIgzip;
-
-   return new debSrcRecordParser(SourcesURI,this);
+   std::vector<std::string> types = APT::Configuration::getCompressionTypes();
+   for (std::vector<std::string>::const_iterator t = types.begin(); t != types.end(); ++t)
+   {
+      string p;
+      p = SourcesURI + '.' + *t;
+      if (FileExists(p))
+         return new debSrcRecordParser(p, this);
+   }
+   if (FileExists(SourcesURI))
+      return new debSrcRecordParser(SourcesURI, this);
+   return NULL;
 }
 									/*}}}*/
 // SourcesIndex::Describe - Give a descriptive path to the index	/*{{{*/
@@ -127,14 +131,18 @@ string debSourcesIndex::Info(const char *Type) const
 // SourcesIndex::Index* - Return the URI to the index files		/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-inline string debSourcesIndex::IndexFile(const char *Type) const
+string debSourcesIndex::IndexFile(const char *Type) const
 {
    string s = URItoFileName(IndexURI(Type));
-   string sgzip = s + ".gz";
-   if (!FileExists(s) && FileExists(sgzip))
-       return sgzip;
-   else
-       return s;
+
+   std::vector<std::string> types = APT::Configuration::getCompressionTypes();
+   for (std::vector<std::string>::const_iterator t = types.begin(); t != types.end(); ++t)
+   {
+      string p = s + '.' + *t;
+      if (FileExists(p))
+         return p;
+   }
+   return s;
 }
 
 string debSourcesIndex::IndexURI(const char *Type) const
@@ -257,14 +265,18 @@ string debPackagesIndex::Info(const char *Type) const
 // PackagesIndex::Index* - Return the URI to the index files		/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-inline string debPackagesIndex::IndexFile(const char *Type) const
+string debPackagesIndex::IndexFile(const char *Type) const
 {
    string s =_config->FindDir("Dir::State::lists") + URItoFileName(IndexURI(Type));
-   string sgzip = s + ".gz";
-   if (!FileExists(s) && FileExists(sgzip))
-       return sgzip;
-   else
-       return s;
+
+   std::vector<std::string> types = APT::Configuration::getCompressionTypes();
+   for (std::vector<std::string>::const_iterator t = types.begin(); t != types.end(); ++t)
+   {
+      string p = s + '.' + *t;
+      if (FileExists(p))
+         return p;
+   }
+   return s;
 }
 string debPackagesIndex::IndexURI(const char *Type) const
 {
@@ -409,14 +421,18 @@ debTranslationsIndex::debTranslationsIndex(string URI,string Dist,string Section
 // TranslationIndex::Trans* - Return the URI to the translation files	/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-inline string debTranslationsIndex::IndexFile(const char *Type) const
+string debTranslationsIndex::IndexFile(const char *Type) const
 {
    string s =_config->FindDir("Dir::State::lists") + URItoFileName(IndexURI(Type));
-   string sgzip = s + ".gz";
-   if (!FileExists(s) && FileExists(sgzip))
-       return sgzip;
-   else
-       return s;
+
+   std::vector<std::string> types = APT::Configuration::getCompressionTypes();
+   for (std::vector<std::string>::const_iterator t = types.begin(); t != types.end(); ++t)
+   {
+      string p = s + '.' + *t;
+      if (FileExists(p))
+         return p;
+   }
+   return s;
 }
 string debTranslationsIndex::IndexURI(const char *Type) const
 {
@@ -619,7 +635,7 @@ bool debStatusIndex::Merge(pkgCacheGenerator &Gen,OpProgress *Prog) const
    pkgCache::PkgFileIterator CFile = Gen.GetCurFile();
    CFile->Size = Pkg.FileSize();
    CFile->mtime = Pkg.ModificationTime();
-   map_ptrloc const storage = Gen.WriteUniqString("now");
+   map_stringitem_t const storage = Gen.StoreString(pkgCacheGenerator::MIXED, "now");
    CFile->Archive = storage;
    
    if (Gen.MergeList(Parser) == false)
@@ -692,15 +708,27 @@ bool debDebPkgFileIndex::Merge(pkgCacheGenerator& Gen, OpProgress* Prog) const
 
    // get the control data out of the deb file vid dpkg -I
    // ... can I haz libdpkg?
+   Configuration::Item const *Opts = _config->Tree("DPkg::Options");
    std::string dpkg = _config->Find("Dir::Bin::dpkg","dpkg");
-   const char *Args[5] = {dpkg.c_str(),
-                          "-I",
-                          DebFile.c_str(),
-                          "control",
-                          NULL};
+   std::vector<const char *> Args;
+   Args.push_back(dpkg.c_str());
+   if (Opts != 0)
+   {
+      Opts = Opts->Child;
+      for (; Opts != 0; Opts = Opts->Next)
+      {
+	 if (Opts->Value.empty() == true)
+	    continue;
+	 Args.push_back(Opts->Value.c_str());
+      }
+   }
+   Args.push_back("-I");
+   Args.push_back(DebFile.c_str());
+   Args.push_back("control");
+   Args.push_back(NULL);
    FileFd PipeFd;
    pid_t Child;
-   if(Popen(Args, PipeFd, Child, FileFd::ReadOnly) == false)
+   if(Popen((const char**)&Args[0], PipeFd, Child, FileFd::ReadOnly) == false)
       return _error->Error("Popen failed");
    // FIXME: static buffer
    char buf[8*1024];
@@ -710,7 +738,7 @@ bool debDebPkgFileIndex::Merge(pkgCacheGenerator& Gen, OpProgress* Prog) const
    ExecWait(Child, "Popen");
 
    // now write the control data to a tempfile
-   SPtr<FileFd> DebControl = GetTempFile("deb-file-" + DebFile);
+   SPtr<FileFd> DebControl = GetTempFile("deb-file-" + flNotDir(DebFile));
    if(DebControl == NULL)
       return false;
    DebControl->Write(buf, n);
@@ -738,8 +766,6 @@ bool debDebPkgFileIndex::Merge(pkgCacheGenerator& Gen, OpProgress* Prog) const
 }
 pkgCache::PkgFileIterator debDebPkgFileIndex::FindInCache(pkgCache &Cache) const
 {
-   // FIXME: we could simply always return pkgCache::PkgFileIterator(Cache);
-   //        to indicate its never in the cache which will force a Merge()
    pkgCache::PkgFileIterator File = Cache.FileBegin();
    for (; File.end() == false; ++File)
    {

+ 13 - 12
apt-pkg/deb/debindexfile.h

@@ -65,10 +65,10 @@ class debPackagesIndex : public pkgIndexFile
    std::string Section;
    std::string Architecture;
 
-   std::string Info(const char *Type) const;
-   std::string IndexFile(const char *Type) const;
-   std::string IndexURI(const char *Type) const;
-   
+   APT_HIDDEN std::string Info(const char *Type) const;
+   APT_HIDDEN std::string IndexFile(const char *Type) const;
+   APT_HIDDEN std::string IndexURI(const char *Type) const;
+
    public:
    
    virtual const Type *GetType() const APT_CONST;
@@ -102,11 +102,11 @@ class debTranslationsIndex : public pkgIndexFile
    std::string Section;
    const char * const Language;
    
-   std::string Info(const char *Type) const;
-   std::string IndexFile(const char *Type) const;
-   std::string IndexURI(const char *Type) const;
+   APT_HIDDEN std::string Info(const char *Type) const;
+   APT_HIDDEN std::string IndexFile(const char *Type) const;
+   APT_HIDDEN std::string IndexURI(const char *Type) const;
 
-   inline std::string TranslationFile() const {return std::string("Translation-").append(Language);};
+   APT_HIDDEN std::string TranslationFile() const {return std::string("Translation-").append(Language);};
 
    public:
    
@@ -136,10 +136,10 @@ class debSourcesIndex : public pkgIndexFile
    std::string Dist;
    std::string Section;
 
-   std::string Info(const char *Type) const;
-   std::string IndexFile(const char *Type) const;
-   std::string IndexURI(const char *Type) const;
-   
+   APT_HIDDEN std::string Info(const char *Type) const;
+   APT_HIDDEN std::string IndexFile(const char *Type) const;
+   APT_HIDDEN std::string IndexURI(const char *Type) const;
+
    public:
 
    virtual const Type *GetType() const APT_CONST;
@@ -214,6 +214,7 @@ class debDscFileIndex : public pkgIndexFile
 
 class debDebianSourceDirIndex : public debDscFileIndex
 {
+ public:
    virtual const Type *GetType() const APT_CONST;
 };
 

+ 73 - 31
apt-pkg/deb/deblistparser.cc

@@ -58,18 +58,6 @@ debListParser::debListParser(FileFd *File, string const &Arch) : Tags(File),
    MultiArchEnabled = Architectures.size() > 1;
 }
 									/*}}}*/
-// ListParser::UniqFindTagWrite - Find the tag and write a unq string	/*{{{*/
-// ---------------------------------------------------------------------
-/* */
-unsigned long debListParser::UniqFindTagWrite(const char *Tag)
-{
-   const char *Start;
-   const char *Stop;
-   if (Section.Find(Tag,Start,Stop) == false)
-      return 0;
-   return WriteUniqString(Start,Stop - Start);
-}
-									/*}}}*/
 // ListParser::Package - Return the package name			/*{{{*/
 // ---------------------------------------------------------------------
 /* This is to return the name of the package this section describes */
@@ -108,7 +96,7 @@ unsigned char debListParser::ParseMultiArch(bool const showErrors)	/*{{{*/
 {
    unsigned char MA;
    string const MultiArch = Section.FindS("Multi-Arch");
-   if (MultiArch.empty() == true)
+   if (MultiArch.empty() == true || MultiArch == "no")
       MA = pkgCache::Version::None;
    else if (MultiArch == "same") {
       if (ArchitectureAll() == true)
@@ -144,8 +132,67 @@ unsigned char debListParser::ParseMultiArch(bool const showErrors)	/*{{{*/
 /* */
 bool debListParser::NewVersion(pkgCache::VerIterator &Ver)
 {
+   const char *Start;
+   const char *Stop;
+
    // Parse the section
-   Ver->Section = UniqFindTagWrite("Section");
+   if (Section.Find("Section",Start,Stop) == true)
+   {
+      map_stringitem_t const idx = StoreString(pkgCacheGenerator::SECTION, Start, Stop - Start);
+      Ver->Section = idx;
+   }
+   // Parse the source package name
+   pkgCache::GrpIterator const G = Ver.ParentPkg().Group();
+   Ver->SourcePkgName = G->Name;
+   Ver->SourceVerStr = Ver->VerStr;
+   if (Section.Find("Source",Start,Stop) == true)
+   {
+      const char * const Space = (const char * const) memchr(Start, ' ', Stop - Start);
+      pkgCache::VerIterator V;
+
+      if (Space != NULL)
+      {
+	 Stop = Space;
+	 const char * const Open = (const char * const) memchr(Space, '(', Stop - Space);
+	 if (likely(Open != NULL))
+	 {
+	    const char * const Close = (const char * const) memchr(Open, ')', Stop - Open);
+	    if (likely(Close != NULL))
+	    {
+	       std::string const version(Open + 1, (Close - Open) - 1);
+	       if (version != Ver.VerStr())
+	       {
+		  map_stringitem_t const idx = StoreString(pkgCacheGenerator::VERSIONNUMBER, version);
+		  Ver->SourceVerStr = idx;
+	       }
+	    }
+	 }
+      }
+
+      std::string const pkgname(Start, Stop - Start);
+      if (pkgname != G.Name())
+      {
+	 for (pkgCache::PkgIterator P = G.PackageList(); P.end() == false; P = G.NextPkg(P))
+	 {
+	    for (V = P.VersionList(); V.end() == false; ++V)
+	    {
+	       if (pkgname == V.SourcePkgName())
+	       {
+		  Ver->SourcePkgName = V->SourcePkgName;
+		  break;
+	       }
+	    }
+	    if (V.end() == false)
+	       break;
+	 }
+	 if (V.end() == true)
+	 {
+	    map_stringitem_t const idx = StoreString(pkgCacheGenerator::PKGNAME, pkgname);
+	    Ver->SourcePkgName = idx;
+	 }
+      }
+   }
+
    Ver->MultiArch = ParseMultiArch(true);
    // Archive Size
    Ver->Size = Section.FindULL("Size");
@@ -154,10 +201,8 @@ bool debListParser::NewVersion(pkgCache::VerIterator &Ver)
    Ver->InstalledSize *= 1024;
 
    // Priority
-   const char *Start;
-   const char *Stop;
    if (Section.Find("Priority",Start,Stop) == true)
-   {      
+   {
       if (GrabWord(string(Start,Stop-Start),PrioList,Ver->Priority) == false)
 	 Ver->Priority = pkgCache::State::Extra;
    }
@@ -255,9 +300,6 @@ MD5SumValue debListParser::Description_md5()
 bool debListParser::UsePackage(pkgCache::PkgIterator &Pkg,
 			       pkgCache::VerIterator &Ver)
 {
-   if (Pkg->Section == 0)
-      Pkg->Section = UniqFindTagWrite("Section");
-
    string const static myArch = _config->Find("APT::Architecture");
    // Possible values are: "all", "native", "installed" and "none"
    // The "installed" mode is handled by ParseStatus(), See #544481 and friends.
@@ -795,8 +837,8 @@ bool debListParser::ParseProvides(pkgCache::VerIterator &Ver)
 	 Start = ParseDepends(Start,Stop,Package,Version,Op);
 	 if (Start == 0)
 	    return _error->Error("Problem parsing Provides line");
-	 if (Op != pkgCache::Dep::NoOp) {
-	    _error->Warning("Ignoring Provides line with DepCompareOp for package %s", Package.c_str());
+	 if (Op != pkgCache::Dep::NoOp && Op != pkgCache::Dep::Equals) {
+	    _error->Warning("Ignoring Provides line with non-equal DepCompareOp for package %s", Package.c_str());
 	 } else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign) {
 	    if (NewProvidesAllArch(Ver, Package, Version) == false)
 	       return false;
@@ -893,7 +935,7 @@ bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator &FileI,
 {
    // apt-secure does no longer download individual (per-section) Release
    // file. to provide Component pinning we use the section name now
-   map_ptrloc const storage = WriteUniqString(component);
+   map_stringitem_t const storage = StoreString(pkgCacheGenerator::MIXED, component);
    FileI->Component = storage;
 
    pkgTagFile TagFile(&File, File.Size());
@@ -902,19 +944,19 @@ bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator &FileI,
       return false;
 
    std::string data;
-   #define APT_INRELEASE(TAG, STORE) \
+   #define APT_INRELEASE(TYPE, TAG, STORE) \
    data = Section.FindS(TAG); \
    if (data.empty() == false) \
    { \
-      map_ptrloc const storage = WriteUniqString(data); \
+      map_stringitem_t const storage = StoreString(pkgCacheGenerator::TYPE, data); \
       STORE = storage; \
    }
-   APT_INRELEASE("Suite", FileI->Archive)
-   APT_INRELEASE("Component", FileI->Component)
-   APT_INRELEASE("Version", FileI->Version)
-   APT_INRELEASE("Origin", FileI->Origin)
-   APT_INRELEASE("Codename", FileI->Codename)
-   APT_INRELEASE("Label", FileI->Label)
+   APT_INRELEASE(MIXED, "Suite", FileI->Archive)
+   APT_INRELEASE(MIXED, "Component", FileI->Component)
+   APT_INRELEASE(VERSIONNUMBER, "Version", FileI->Version)
+   APT_INRELEASE(MIXED, "Origin", FileI->Origin)
+   APT_INRELEASE(MIXED, "Codename", FileI->Codename)
+   APT_INRELEASE(MIXED, "Label", FileI->Label)
    #undef APT_INRELEASE
    Section.FindFlag("NotAutomatic", FileI->Flags, pkgCache::Flag::NotAutomatic);
    Section.FindFlag("ButAutomaticUpgrades", FileI->Flags, pkgCache::Flag::ButAutomaticUpgrades);

+ 3 - 4
apt-pkg/deb/deblistparser.h

@@ -44,12 +44,11 @@ class debListParser : public pkgCacheGenerator::ListParser
    protected:
    pkgTagFile Tags;
    pkgTagSection Section;
-   unsigned long iOffset;
+   map_filesize_t iOffset;
    std::string Arch;
    std::vector<std::string> Architectures;
    bool MultiArchEnabled;
 
-   unsigned long UniqFindTagWrite(const char *Tag);
    virtual bool ParseStatus(pkgCache::PkgIterator &Pkg,pkgCache::VerIterator &Ver);
    bool ParseDepends(pkgCache::VerIterator &Ver,const char *Tag,
 		     unsigned int Type);
@@ -77,8 +76,8 @@ class debListParser : public pkgCacheGenerator::ListParser
 #endif
    virtual bool UsePackage(pkgCache::PkgIterator &Pkg,
 			   pkgCache::VerIterator &Ver);
-   virtual unsigned long Offset() {return iOffset;};
-   virtual unsigned long Size() {return Section.size();};
+   virtual map_filesize_t Offset() {return iOffset;};
+   virtual map_filesize_t Size() {return Section.size();};
 
    virtual bool Step();
    

+ 1 - 1
apt-pkg/deb/debmetaindex.h

@@ -36,7 +36,7 @@ class debReleaseIndex : public metaIndex {
    /** \brief dpointer placeholder (for later in case we need it) */
    void *d;
    std::map<std::string, std::vector<debSectionEntry const*> > ArchEntries;
-   enum { ALWAYS_TRUSTED, NEVER_TRUSTED, CHECK_TRUST } Trusted;
+   enum APT_HIDDEN { ALWAYS_TRUSTED, NEVER_TRUSTED, CHECK_TRUST } Trusted;
 
    public:
 

+ 2 - 1
apt-pkg/deb/debsrcrecords.cc

@@ -239,7 +239,8 @@ bool debSrcRecordParser::Files(std::vector<pkgSrcRecords::File> &List)
 /* */
 debSrcRecordParser::~debSrcRecordParser()
 {
-   delete[] Buffer;
+   // was allocated via strndup()
+   free(Buffer);
 }
 									/*}}}*/
 

+ 1 - 1
apt-pkg/deb/debsystem.h

@@ -29,7 +29,7 @@ class debSystem : public pkgSystem
 {
    // private d-pointer
    debSystemPrivate *d;
-   bool CheckUpdates();
+   APT_HIDDEN bool CheckUpdates();
 
    public:
 

+ 158 - 111
apt-pkg/deb/dpkgpm.cc

@@ -59,8 +59,8 @@ class pkgDPkgPMPrivate
 {
 public:
    pkgDPkgPMPrivate() : stdin_is_dev_null(false), dpkgbuf_pos(0),
-			term_out(NULL), history_out(NULL), 
-                        progress(NULL), master(-1), slave(-1)
+			term_out(NULL), history_out(NULL),
+                        progress(NULL), master(-1), slave(NULL)
    {
       dpkgbuf[0] = '\0';
    }
@@ -77,9 +77,9 @@ public:
    APT::Progress::PackageManager *progress;
 
    // pty stuff
-   struct	termios tt;
+   struct termios tt;
    int master;
-   int slave;
+   char * slave;
 
    // signals
    sigset_t sigmask;
@@ -510,7 +510,7 @@ bool pkgDPkgPM::RunScriptsWithPkgs(const char *Cnf)
    return result;
 }
 									/*}}}*/
-// DPkgPM::DoStdin - Read stdin and pass to slave pty			/*{{{*/
+// DPkgPM::DoStdin - Read stdin and pass to master pty			/*{{{*/
 // ---------------------------------------------------------------------
 /*
 */
@@ -564,8 +564,8 @@ void pkgDPkgPM::ProcessDpkgStatusLine(char *line)
       'status:   <pkg>: <pkg  qstate>'
       'status:   <pkg>:<arch>: <pkg  qstate>'
       
-      'processing: {install,configure,remove,purge,disappear,trigproc}: pkg'
-      'processing: {install,configure,remove,purge,disappear,trigproc}: trigger'
+      'processing: {install,upgrade,configure,remove,purge,disappear,trigproc}: pkg'
+      'processing: {install,upgrade,configure,remove,purge,disappear,trigproc}: trigger'
    */
 
    // we need to split on ": " (note the appended space) as the ':' is
@@ -589,12 +589,15 @@ void pkgDPkgPM::ProcessDpkgStatusLine(char *line)
    std::string action;
 
    // "processing" has the form "processing: action: pkg or trigger"
-   // with action = ["install", "configure", "remove", "purge", "disappear",
-   //                "trigproc"]
+   // with action = ["install", "upgrade", "configure", "remove", "purge",
+   //                "disappear", "trigproc"]
    if (prefix == "processing")
    {
       pkgname = APT::String::Strip(list[2]);
       action = APT::String::Strip(list[1]);
+      // we don't care for the difference (as dpkg doesn't really either)
+      if (action == "upgrade")
+	 action = "install";
    }
    // "status" has the form: "status: pkg: state"
    // with state in ["half-installed", "unpacked", "half-configured", 
@@ -621,15 +624,15 @@ void pkgDPkgPM::ProcessDpkgStatusLine(char *line)
    {
       if(action == "error")
       {
-         d->progress->Error(list[1], PackagesDone, PackagesTotal,
+         d->progress->Error(pkgname, PackagesDone, PackagesTotal,
                             list[3]);
          pkgFailures++;
-         WriteApportReport(list[1].c_str(), list[3].c_str());
+         WriteApportReport(pkgname.c_str(), list[3].c_str());
          return;
       }
       else if(action == "conffile-prompt")
       {
-         d->progress->ConffilePrompt(list[1], PackagesDone, PackagesTotal,
+         d->progress->ConffilePrompt(pkgname, PackagesDone, PackagesTotal,
                                      list[3]);
          return;
       }
@@ -638,27 +641,26 @@ void pkgDPkgPM::ProcessDpkgStatusLine(char *line)
    // at this point we know that we should have a valid pkgname, so build all 
    // the info from it
 
-   // dpkg does not send always send "pkgname:arch" so we add it here 
-   // if needed
+   // dpkg does not always send "pkgname:arch" so we add it here if needed
    if (pkgname.find(":") == std::string::npos)
    {
-      // find the package in the group that is in a touched by dpkg
-      // if there are multiple dpkg will send us a full pkgname:arch
+      // find the package in the group that is touched by dpkg
+      // if there are multiple pkgs dpkg would send us a full pkgname:arch
       pkgCache::GrpIterator Grp = Cache.FindGrp(pkgname);
-      if (Grp.end() == false) 
+      if (Grp.end() == false)
       {
-          pkgCache::PkgIterator P = Grp.PackageList();
-          for (; P.end() != true; P = Grp.NextPkg(P))
-          {
-              if(Cache[P].Mode != pkgDepCache::ModeKeep)
-              {
-                  pkgname = P.FullName();
-                  break;
-              }
-          }
+	 pkgCache::PkgIterator P = Grp.PackageList();
+	 for (; P.end() != true; P = Grp.NextPkg(P))
+	 {
+	    if(Cache[P].Keep() == false || Cache[P].ReInstall() == true)
+	    {
+	       pkgname = P.FullName();
+	       break;
+	    }
+	 }
       }
    }
-   
+
    const char* const pkg = pkgname.c_str();
    std::string short_pkgname = StringSplit(pkgname, ":")[0];
    std::string arch = "";
@@ -697,28 +699,29 @@ void pkgDPkgPM::ProcessDpkgStatusLine(char *line)
    if (prefix == "status")
    {
       vector<struct DpkgState> const &states = PackageOps[pkg];
-      const char *next_action = NULL;
       if(PackageOpsDone[pkg] < states.size())
-         next_action = states[PackageOpsDone[pkg]].state;
-      // check if the package moved to the next dpkg state
-      if(next_action && (action == next_action))
       {
-         // only read the translation if there is actually a next
-         // action
-         const char *translation = _(states[PackageOpsDone[pkg]].str);
-         std::string msg;
-
-         // we moved from one dpkg state to a new one, report that
-         PackageOpsDone[pkg]++;
-         PackagesDone++;
-
-         strprintf(msg, translation, i18n_pkgname.c_str());
-         d->progress->StatusChanged(pkgname, PackagesDone, PackagesTotal, msg);
-         
+         char const * const next_action = states[PackageOpsDone[pkg]].state;
+	 if (next_action && Debug == true)
+	    std::clog << "(parsed from dpkg) pkg: " << short_pkgname
+	       << " action: " << action << " (expected: '" << next_action << "' "
+	       << PackageOpsDone[pkg] << " of " << states.size() << ")" << endl;
+
+	 // check if the package moved to the next dpkg state
+	 if(next_action && (action == next_action))
+	 {
+	    // only read the translation if there is actually a next action
+	    char const * const translation = _(states[PackageOpsDone[pkg]].str);
+
+	    // we moved from one dpkg state to a new one, report that
+	    ++PackageOpsDone[pkg];
+	    ++PackagesDone;
+
+	    std::string msg;
+	    strprintf(msg, translation, i18n_pkgname.c_str());
+	    d->progress->StatusChanged(pkgname, PackagesDone, PackagesTotal, msg);
+	 }
       }
-      if (Debug == true) 
-         std::clog << "(parsed from dpkg) pkg: " << short_pkgname
-                   << " action: " << action << endl;
    }
 }
 									/*}}}*/
@@ -1031,7 +1034,6 @@ void pkgDPkgPM::BuildPackagesProgressMap()
    }
 }
                                                                         /*}}}*/
-#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR < 13)
 bool pkgDPkgPM::Go(int StatusFd)
 {
    APT::Progress::PackageManager *progress = NULL;
@@ -1040,68 +1042,134 @@ bool pkgDPkgPM::Go(int StatusFd)
    else
       progress = new APT::Progress::PackageManagerProgressFd(StatusFd);
    
-   return GoNoABIBreak(progress);
+   return Go(progress);
 }
-#endif
 
 void pkgDPkgPM::StartPtyMagic()
 {
    if (_config->FindB("Dpkg::Use-Pty", true) == false)
    {
-      d->master = d->slave = -1;
+      d->master = -1;
+      if (d->slave != NULL)
+	 free(d->slave);
+      d->slave = NULL;
       return;
    }
 
-   // setup the pty and stuff
-   struct winsize win;
-
+   _error->PushToStack();
    // if tcgetattr for both stdin/stdout returns 0 (no error)
    // we do the pty magic
-   _error->PushToStack();
-   if (tcgetattr(STDIN_FILENO, &d->tt) == 0 &&
-       tcgetattr(STDOUT_FILENO, &d->tt) == 0)
+   if (tcgetattr(STDOUT_FILENO, &d->tt) == 0 &&
+	 tcgetattr(STDIN_FILENO, &d->tt) == 0)
    {
-       if (ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&win) < 0)
-       {
-           _error->Errno("ioctl", _("ioctl(TIOCGWINSZ) failed"));
-       } else if (openpty(&d->master, &d->slave, NULL, &d->tt, &win) < 0)
-       {
-           _error->Errno("openpty", _("Can not write log (%s)"), _("Is /dev/pts mounted?"));
-           d->master = d->slave = -1;
-        } else {
-	    struct termios rtt;
-	    rtt = d->tt;
-	    cfmakeraw(&rtt);
-	    rtt.c_lflag &= ~ECHO;
-	    rtt.c_lflag |= ISIG;
+      d->master = posix_openpt(O_RDWR | O_NOCTTY);
+      if (d->master == -1)
+	 _error->Errno("posix_openpt", _("Can not write log (%s)"), _("Is /dev/pts mounted?"));
+      else if (unlockpt(d->master) == -1)
+      {
+	 _error->Errno("unlockpt", "Unlocking the slave of master fd %d failed!", d->master);
+	 close(d->master);
+	 d->master = -1;
+      }
+      else
+      {
+	 char const * const slave_name = ptsname(d->master);
+	 if (slave_name == NULL)
+	 {
+	    _error->Errno("unlockpt", "Getting name for slave of master fd %d failed!", d->master);
+	    close(d->master);
+	    d->master = -1;
+	 }
+	 else
+	 {
+	    d->slave = strdup(slave_name);
+	    if (d->slave == NULL)
+	    {
+	       _error->Errno("strdup", "Copying name %s for slave of master fd %d failed!", slave_name, d->master);
+	       close(d->master);
+	       d->master = -1;
+	    }
+	    struct winsize win;
+	    if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) < 0)
+	       _error->Errno("ioctl", "Getting TIOCGWINSZ from stdout failed!");
+	    if (ioctl(d->master, TIOCSWINSZ, &win) < 0)
+	       _error->Errno("ioctl", "Setting TIOCSWINSZ for master fd %d failed!", d->master);
+	    if (tcsetattr(d->master, TCSANOW, &d->tt) == -1)
+	       _error->Errno("tcsetattr", "Setting in Start via TCSANOW for master fd %d failed!", d->master);
+
+	    struct termios raw_tt;
+	    raw_tt = d->tt;
+	    cfmakeraw(&raw_tt);
+	    raw_tt.c_lflag &= ~ECHO;
+	    raw_tt.c_lflag |= ISIG;
 	    // block SIGTTOU during tcsetattr to prevent a hang if
 	    // the process is a member of the background process group
 	    // http://www.opengroup.org/onlinepubs/000095399/functions/tcsetattr.html
 	    sigemptyset(&d->sigmask);
 	    sigaddset(&d->sigmask, SIGTTOU);
 	    sigprocmask(SIG_BLOCK,&d->sigmask, &d->original_sigmask);
-	    tcsetattr(0, TCSAFLUSH, &rtt);
-	    sigprocmask(SIG_SETMASK, &d->original_sigmask, 0);
-        }
+	    if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw_tt) == -1)
+	       _error->Errno("tcsetattr", "Setting in Start via TCSAFLUSH for stdout failed!");
+	    sigprocmask(SIG_SETMASK, &d->original_sigmask, NULL);
+	 }
       }
-   // complain only if stdout is either a terminal (but still failed) or is an invalid
+   }
+   else
+   {
+      // complain only if stdout is either a terminal (but still failed) or is an invalid
       // descriptor otherwise we would complain about redirection to e.g. /dev/null as well.
-      else if (isatty(STDOUT_FILENO) == 1 || errno == EBADF)
-         _error->Errno("tcgetattr", _("Can not write log (%s)"), _("Is stdout a terminal?"));
+      if (isatty(STDOUT_FILENO) == 1 || errno == EBADF)
+	 _error->Errno("tcgetattr", _("Can not write log (%s)"), _("Is stdout a terminal?"));
+   }
 
-      if (_error->PendingError() == true)
-	 _error->DumpErrors(std::cerr);
-      _error->RevertToStack();
+   if (_error->PendingError() == true)
+   {
+      if (d->master != -1)
+      {
+	 close(d->master);
+	 d->master = -1;
+      }
+      _error->DumpErrors(std::cerr);
+   }
+   _error->RevertToStack();
 }
+void pkgDPkgPM::SetupSlavePtyMagic()
+{
+   if(d->master == -1)
+      return;
+
+   if (close(d->master) == -1)
+      _error->FatalE("close", "Closing master %d in child failed!", d->master);
+   if (setsid() == -1)
+      _error->FatalE("setsid", "Starting a new session for child failed!");
+
+   int const slaveFd = open(d->slave, O_RDWR);
+   if (slaveFd == -1)
+      _error->FatalE("open", _("Can not write log (%s)"), _("Is /dev/pts mounted?"));
+
+   if (ioctl(slaveFd, TIOCSCTTY, 0) < 0)
+      _error->FatalE("ioctl", "Setting TIOCSCTTY for slave fd %d failed!", slaveFd);
+   else
+   {
+      for (unsigned short i = 0; i < 3; ++i)
+	 if (dup2(slaveFd, i) == -1)
+	    _error->FatalE("dup2", "Dupping %d to %d in child failed!", slaveFd, i);
 
+      if (tcsetattr(0, TCSANOW, &d->tt) < 0)
+	 _error->FatalE("tcsetattr", "Setting in Setup via TCSANOW for slave fd %d failed!", slaveFd);
+   }
+}
 void pkgDPkgPM::StopPtyMagic()
 {
-   if(d->slave > 0)
-      close(d->slave);
+   if (d->slave != NULL)
+      free(d->slave);
+   d->slave = NULL;
    if(d->master >= 0) 
    {
-      tcsetattr(0, TCSAFLUSH, &d->tt);
+      if (tcsetattr(0, TCSAFLUSH, &d->tt) == -1)
+	 _error->FatalE("tcsetattr", "Setting in Stop via TCSAFLUSH for stdin failed!");
       close(d->master);
+      d->master = -1;
    }
 }
 
@@ -1114,11 +1182,7 @@ void pkgDPkgPM::StopPtyMagic()
  * through to human readable (and i10n-able)
  * names and calculates a percentage for each step.
  */
-#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 13)
 bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
-#else
-bool pkgDPkgPM::GoNoABIBreak(APT::Progress::PackageManager *progress)
-#endif
 {
    pkgPackageManager::SigINTStop = false;
    d->progress = progress;
@@ -1413,22 +1477,8 @@ bool pkgDPkgPM::GoNoABIBreak(APT::Progress::PackageManager *progress)
       pid_t Child = ExecFork(KeepFDs);
       if (Child == 0)
       {
-         // This is the child
-	 if(d->slave >= 0 && d->master >= 0) 
-	 {
-	    setsid();
-	    int res = ioctl(d->slave, TIOCSCTTY, 0);
-            if (res < 0) {
-               std::cerr << "ioctl(TIOCSCTTY) failed for fd: " 
-                         << d->slave << std::endl;
-            } else {
-               close(d->master);
-               dup2(d->slave, 0);
-               dup2(d->slave, 1);
-               dup2(d->slave, 2);
-               close(d->slave);
-            }
-	 }
+	 // This is the child
+	 SetupSlavePtyMagic();
 	 close(fd[0]); // close the read end of the pipe
 
 	 dpkgChrootDirectory();
@@ -1438,7 +1488,8 @@ bool pkgDPkgPM::GoNoABIBreak(APT::Progress::PackageManager *progress)
 
 	 if (_config->FindB("DPkg::FlushSTDIN",true) == true && isatty(STDIN_FILENO))
 	 {
-	    int Flags,dummy;
+	    int Flags;
+            int dummy = 0;
 	    if ((Flags = fcntl(STDIN_FILENO,F_GETFL,dummy)) < 0)
 	       _exit(100);
 	    
@@ -1667,9 +1718,10 @@ void pkgDPkgPM::WriteApportReport(const char *pkgpath, const char *errormsg)
    // do not report dpkg I/O errors, this is a format string, so we compare
    // the prefix and the suffix of the error with the dpkg error message
    vector<string> io_errors;
-   io_errors.push_back(string("failed to read on buffer copy for %s"));
-   io_errors.push_back(string("failed in write on buffer copy for %s"));
-   io_errors.push_back(string("short read on buffer copy for %s"));
+   io_errors.push_back(string("failed to read"));
+   io_errors.push_back(string("failed to write"));
+   io_errors.push_back(string("failed to seek"));
+   io_errors.push_back(string("unexpected end of file or stream"));
 
    for (vector<string>::iterator I = io_errors.begin(); I != io_errors.end(); ++I)
    {
@@ -1702,11 +1754,6 @@ void pkgDPkgPM::WriteApportReport(const char *pkgpath, const char *errormsg)
    if (Ver.end() == true)
       return;
    pkgver = Ver.VerStr() == NULL ? "unknown" : Ver.VerStr();
-   pkgRecords Recs(Cache);
-   pkgRecords::Parser &Parse = Recs.Lookup(Ver.FileList());
-   srcpkgname = Parse.SourcePkg();
-   if(srcpkgname.empty())
-      srcpkgname = pkgname;
 
    // if the file exists already, we check:
    // - if it was reported already (touched by apport). 
@@ -1757,7 +1804,7 @@ void pkgDPkgPM::WriteApportReport(const char *pkgpath, const char *errormsg)
    time_t now = time(NULL);
    fprintf(report, "Date: %s" , ctime(&now));
    fprintf(report, "Package: %s %s\n", pkgname.c_str(), pkgver.c_str());
-   fprintf(report, "SourcePackage: %s\n", srcpkgname.c_str());
+   fprintf(report, "SourcePackage: %s\n", Ver.SourcePkgName());
    fprintf(report, "ErrorMessage:\n %s\n", errormsg);
 
    // ensure that the log is flushed

+ 2 - 14
apt-pkg/deb/dpkgpm.h

@@ -52,7 +52,7 @@ class pkgDPkgPM : public pkgPackageManager
       needs to declare a Replaces on the disappeared package.
       \param pkgname Name of the package that disappeared
    */
-   void handleDisappearAction(std::string const &pkgname);
+   APT_HIDDEN void handleDisappearAction(std::string const &pkgname);
 
    protected:
    int pkgFailures;
@@ -110,6 +110,7 @@ class pkgDPkgPM : public pkgPackageManager
    // helper
    void BuildPackagesProgressMap();
    void StartPtyMagic();
+   void SetupSlavePtyMagic();
    void StopPtyMagic();
    
    // input processing
@@ -117,27 +118,14 @@ class pkgDPkgPM : public pkgPackageManager
    void DoTerminalPty(int master);
    void DoDpkgStatusFd(int statusfd);
    void ProcessDpkgStatusLine(char *line);
-#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR < 13)
-   void DoDpkgStatusFd(int statusfd, int /*unused*/) {
-      DoDpkgStatusFd(statusfd);
-   }
-   void ProcessDpkgStatusLine(int /*unused*/, char *line) {
-      ProcessDpkgStatusLine(line);
-   }
-#endif
-
 
    // The Actuall installation implementation
    virtual bool Install(PkgIterator Pkg,std::string File);
    virtual bool Configure(PkgIterator Pkg);
    virtual bool Remove(PkgIterator Pkg,bool Purge = false);
 
-#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 13)
    virtual bool Go(APT::Progress::PackageManager *progress);
-#else
    virtual bool Go(int StatusFd=-1);
-   bool GoNoABIBreak(APT::Progress::PackageManager *progress);
-#endif
 
    virtual void Reset();
    

+ 19 - 4
apt-pkg/depcache.cc

@@ -663,10 +663,11 @@ void pkgDepCache::Update(OpProgress *Prog)
 {   
    iUsrSize = 0;
    iDownloadSize = 0;
-   iDelCount = 0;
    iInstCount = 0;
+   iDelCount = 0;
    iKeepCount = 0;
    iBrokenCount = 0;
+   iPolicyBrokenCount = 0;
    iBadCount = 0;
 
    // Perform the depends pass
@@ -1225,7 +1226,7 @@ bool pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
 	       continue;
 	    }
 	    // now check if we should consider it a automatic dependency or not
-	    if(InstPkg->CurrentVer == 0 && Pkg->Section != 0 && ConfigValueInSubTree("APT::Never-MarkAuto-Sections", Pkg.Section()))
+	    if(InstPkg->CurrentVer == 0 && InstVer->Section != 0 && ConfigValueInSubTree("APT::Never-MarkAuto-Sections", InstVer.Section()))
 	    {
 	       if(DebugAutoInstall == true)
 		  std::clog << OutputInDepth(Depth) << "Setting NOT as auto-installed (direct "
@@ -1374,7 +1375,7 @@ bool pkgDepCache::IsInstallOkDependenciesSatisfiableByCandidates(PkgIterator con
 
 	 // the dependency is critical, but can't be installed, so discard the candidate
 	 // as the problemresolver will trip over it otherwise trying to install it (#735967)
-	 if (Pkg->CurrentVer != 0)
+	 if (Pkg->CurrentVer != 0 && (PkgState[Pkg->ID].iFlags & Protected) != Protected)
 	    SetCandidateVersion(Pkg.CurrentVer());
 	 return false;
       }
@@ -1678,7 +1679,7 @@ pkgCache::VerIterator pkgDepCache::Policy::GetCandidateVer(PkgIterator const &Pk
 {
    /* Not source/not automatic versions cannot be a candidate version 
       unless they are already installed */
-   VerIterator Last(*(pkgCache *)this,0);
+   VerIterator Last;
    
    for (VerIterator I = Pkg.VersionList(); I.end() == false; ++I)
    {
@@ -1960,3 +1961,17 @@ bool pkgDepCache::Sweep()						/*{{{*/
    return true;
 }
 									/*}}}*/
+// DepCache::MarkAndSweep						/*{{{*/
+bool pkgDepCache::MarkAndSweep(InRootSetFunc &rootFunc)
+{
+   return MarkRequired(rootFunc) && Sweep();
+}
+bool pkgDepCache::MarkAndSweep()
+{
+   std::auto_ptr<InRootSetFunc> f(GetRootSetFunc());
+   if(f.get() != NULL)
+      return MarkAndSweep(*f.get());
+   else
+      return false;
+}
+									/*}}}*/

+ 7 - 18
apt-pkg/depcache.h

@@ -91,7 +91,7 @@ class pkgDepCache : protected pkgCache::Namespace
     *  \param follow_suggests If \b true, suggestions of the package
     *  will be recursively marked.
     */
-   void MarkPackage(const pkgCache::PkgIterator &pkg,
+   APT_HIDDEN void MarkPackage(const pkgCache::PkgIterator &pkg,
 		    const pkgCache::VerIterator &ver,
 		    bool const &follow_recommends,
 		    bool const &follow_suggests);
@@ -109,7 +109,7 @@ class pkgDepCache : protected pkgCache::Namespace
     *
     *  \return \b false if an error occurred.
     */
-   bool MarkRequired(InRootSetFunc &rootFunc);
+   APT_HIDDEN bool MarkRequired(InRootSetFunc &rootFunc);
 
    /** \brief Set the StateCache::Garbage flag on all packages that
     *  should be removed.
@@ -120,7 +120,7 @@ class pkgDepCache : protected pkgCache::Namespace
     *
     *  \return \b false if an error occurred.
     */
-   bool Sweep();
+   APT_HIDDEN bool Sweep();
 
    public:
    
@@ -169,7 +169,7 @@ class pkgDepCache : protected pkgCache::Namespace
        bool released;
 
        /** Action groups are noncopyable. */
-       ActionGroup(const ActionGroup &other);
+       APT_HIDDEN ActionGroup(const ActionGroup &other);
    public:
        /** \brief Create a new ActionGroup.
 	*
@@ -396,19 +396,8 @@ class pkgDepCache : protected pkgCache::Namespace
     *  \param rootFunc A predicate that returns \b true for packages
     *  that should be added to the root set.
     */
-   bool MarkAndSweep(InRootSetFunc &rootFunc)
-   {
-     return MarkRequired(rootFunc) && Sweep();
-   }
-
-   bool MarkAndSweep()
-   {
-     std::auto_ptr<InRootSetFunc> f(GetRootSetFunc());
-     if(f.get() != NULL)
-       return MarkAndSweep(*f.get());
-     else
-       return false;
-   }
+   bool MarkAndSweep(InRootSetFunc &rootFunc);
+   bool MarkAndSweep();
 
    /** \name State Manipulators
     */
@@ -514,7 +503,7 @@ class pkgDepCache : protected pkgCache::Namespace
 	 bool const rPurge, unsigned long const Depth, bool const FromUser);
 
    private:
-   bool IsModeChangeOk(ModeList const mode, PkgIterator const &Pkg,
+   APT_HIDDEN bool IsModeChangeOk(ModeList const mode, PkgIterator const &Pkg,
 			unsigned long const Depth, bool const FromUser);
 };
 

+ 62 - 10
apt-pkg/edsp.cc

@@ -18,6 +18,7 @@
 #include <apt-pkg/pkgcache.h>
 #include <apt-pkg/cacheiterators.h>
 #include <apt-pkg/strutl.h>
+#include <apt-pkg/pkgrecords.h>
 
 #include <ctype.h>
 #include <stddef.h>
@@ -25,6 +26,7 @@
 #include <time.h>
 #include <unistd.h>
 #include <stdio.h>
+#include <algorithm>
 #include <iostream>
 #include <vector>
 #include <limits>
@@ -49,7 +51,12 @@ bool EDSP::WriteScenario(pkgDepCache &Cache, FILE* output, OpProgress *Progress)
    if (Progress != NULL)
       Progress->SubProgress(Cache.Head().VersionCount, _("Send scenario to solver"));
    unsigned long p = 0;
+   std::vector<std::string> archs = APT::Configuration::getArchitectures();
    for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg)
+   {
+      std::string const arch = Pkg.Arch();
+      if (std::find(archs.begin(), archs.end(), arch) == archs.end())
+	 continue;
       for (pkgCache::VerIterator Ver = Pkg.VersionList(); Ver.end() == false; ++Ver, ++p)
       {
 	 WriteScenarioVersion(Cache, output, Pkg, Ver);
@@ -58,6 +65,7 @@ bool EDSP::WriteScenario(pkgDepCache &Cache, FILE* output, OpProgress *Progress)
 	 if (Progress != NULL && p % 100 == 0)
 	    Progress->Progress(p);
       }
+   }
    return true;
 }
 									/*}}}*/
@@ -88,6 +96,7 @@ void EDSP::WriteScenarioVersion(pkgDepCache &Cache, FILE* output, pkgCache::PkgI
 				pkgCache::VerIterator const &Ver)
 {
    fprintf(output, "Package: %s\n", Pkg.Name());
+   fprintf(output, "Source: %s\n", Ver.SourcePkgName());
    fprintf(output, "Architecture: %s\n", Ver.Arch());
    fprintf(output, "Version: %s\n", Ver.VerStr());
    if (Pkg.CurrentVer() == Ver)
@@ -107,10 +116,22 @@ void EDSP::WriteScenarioVersion(pkgDepCache &Cache, FILE* output, pkgCache::PkgI
    else if ((Ver->MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same)
       fprintf(output, "Multi-Arch: same\n");
    signed short Pin = std::numeric_limits<signed short>::min();
-   for (pkgCache::VerFileIterator File = Ver.FileList(); File.end() == false; ++File) {
-      signed short const p = Cache.GetPolicy().GetPriority(File.File());
+   std::set<string> Releases;
+   for (pkgCache::VerFileIterator I = Ver.FileList(); I.end() == false; ++I) {
+      pkgCache::PkgFileIterator File = I.File();
+      signed short const p = Cache.GetPolicy().GetPriority(File);
       if (Pin < p)
 	 Pin = p;
+      if ((File->Flags & pkgCache::Flag::NotSource) != pkgCache::Flag::NotSource) {
+	 string Release = File.RelStr();
+	 if (!Release.empty())
+	    Releases.insert(Release);
+      }
+   }
+   if (!Releases.empty()) {
+       fprintf(output, "APT-Release:\n");
+       for (std::set<string>::iterator R = Releases.begin(); R != Releases.end(); ++R)
+	   fprintf(output, " %s\n", R->c_str());
    }
    fprintf(output, "APT-Pin: %d\n", Pin);
    if (Cache.GetCandidateVer(Pkg) == Ver)
@@ -231,7 +252,16 @@ bool EDSP::WriteRequest(pkgDepCache &Cache, FILE* output, bool const Upgrade,
 	 continue;
       req->append(" ").append(Pkg.FullName());
    }
-   fprintf(output, "Request: EDSP 0.4\n");
+   fprintf(output, "Request: EDSP 0.5\n");
+
+   const char *arch = _config->Find("APT::Architecture").c_str();
+   std::vector<string> archs = APT::Configuration::getArchitectures();
+   fprintf(output, "Architecture: %s\n", arch);
+   fprintf(output, "Architectures:");
+   for (std::vector<string>::const_iterator a = archs.begin(); a != archs.end(); ++a)
+       fprintf(output, " %s", a->c_str());
+   fprintf(output, "\n");
+
    if (del.empty() == false)
       fprintf(output, "Remove: %s\n", del.c_str()+1);
    if (inst.empty() == false)
@@ -411,6 +441,13 @@ bool EDSP::ReadRequest(int const input, std::list<std::string> &install,
 	    distUpgrade = EDSP::StringToBool(line.c_str() + 14, false);
 	 else if (line.compare(0, 11, "Autoremove:") == 0)
 	    autoRemove = EDSP::StringToBool(line.c_str() + 12, false);
+	 else if (line.compare(0, 13, "Architecture:") == 0)
+	    _config->Set("APT::Architecture", line.c_str() + 14);
+	 else if (line.compare(0, 14, "Architectures:") == 0)
+	 {
+	    std::string const archs = line.c_str() + 15;
+	    _config->Set("APT::Architectures", SubstVar(archs, " ", ","));
+	 }
 	 else
 	    _error->Warning("Unknown line in EDSP Request stanza: %s", line.c_str());
 
@@ -508,7 +545,7 @@ bool EDSP::WriteError(char const * const uuid, std::string const &message, FILE*
 }
 									/*}}}*/
 // EDSP::ExecuteSolver - fork requested solver and setup ipc pipes	{{{*/
-bool EDSP::ExecuteSolver(const char* const solver, int *solver_in, int *solver_out) {
+pid_t EDSP::ExecuteSolver(const char* const solver, int * const solver_in, int * const solver_out, bool) {
 	std::vector<std::string> const solverDirs = _config->FindVector("Dir::Bin::Solvers");
 	std::string file;
 	for (std::vector<std::string>::const_iterator dir = solverDirs.begin();
@@ -520,10 +557,16 @@ bool EDSP::ExecuteSolver(const char* const solver, int *solver_in, int *solver_o
 	}
 
 	if (file.empty() == true)
-		return _error->Error("Can't call external solver '%s' as it is not in a configured directory!", solver);
+	{
+		_error->Error("Can't call external solver '%s' as it is not in a configured directory!", solver);
+		return 0;
+	}
 	int external[4] = {-1, -1, -1, -1};
 	if (pipe(external) != 0 || pipe(external + 2) != 0)
-		return _error->Errno("Resolve", "Can't create needed IPC pipes for EDSP");
+	{
+		_error->Errno("Resolve", "Can't create needed IPC pipes for EDSP");
+		return 0;
+	}
 	for (int i = 0; i < 4; ++i)
 		SetCloseExec(external[i], true);
 
@@ -540,11 +583,19 @@ bool EDSP::ExecuteSolver(const char* const solver, int *solver_in, int *solver_o
 	close(external[3]);
 
 	if (WaitFd(external[1], true, 5) == false)
-		return _error->Errno("Resolve", "Timed out while Waiting on availability of solver stdin");
+	{
+		_error->Errno("Resolve", "Timed out while Waiting on availability of solver stdin");
+		return 0;
+	}
 
 	*solver_in = external[1];
 	*solver_out = external[2];
-	return true;
+	return Solver;
+}
+bool EDSP::ExecuteSolver(const char* const solver, int *solver_in, int *solver_out) {
+   if (ExecuteSolver(solver, solver_in, solver_out, true) == 0)
+      return false;
+   return true;
 }
 									/*}}}*/
 // EDSP::ResolveExternal - resolve problems by asking external for help	{{{*/
@@ -552,7 +603,8 @@ bool EDSP::ResolveExternal(const char* const solver, pkgDepCache &Cache,
 			 bool const upgrade, bool const distUpgrade,
 			 bool const autoRemove, OpProgress *Progress) {
 	int solver_in, solver_out;
-	if (EDSP::ExecuteSolver(solver, &solver_in, &solver_out) == false)
+	pid_t const solver_pid = EDSP::ExecuteSolver(solver, &solver_in, &solver_out, true);
+	if (solver_pid == 0)
 		return false;
 
 	FILE* output = fdopen(solver_in, "w");
@@ -572,6 +624,6 @@ bool EDSP::ResolveExternal(const char* const solver, pkgDepCache &Cache,
 	if (EDSP::ReadResponse(solver_out, Cache, Progress) == false)
 		return false;
 
-	return true;
+	return ExecWait(solver_pid, solver);
 }
 									/*}}}*/

+ 3 - 3
apt-pkg/edsp.h

@@ -205,10 +205,10 @@ public:
 	 *  \param[out] solver_in will be the stdin of the solver
 	 *  \param[out] solver_out will be the stdout of the solver
 	 *
-	 *  \return true if the solver could be started and the pipes
-	 *  are set up correctly, otherwise false and the pipes are invalid
+	 *  \return PID of the started solver or 0 if failure occurred
 	 */
-	bool static ExecuteSolver(const char* const solver, int *solver_in, int *solver_out);
+	pid_t static ExecuteSolver(const char* const solver, int * const solver_in, int * const solver_out, bool /*overload*/);
+	APT_DEPRECATED bool static ExecuteSolver(const char* const solver, int *solver_in, int *solver_out);
 
 	/** \brief call an external resolver to handle the request
 	 *

+ 1 - 1
apt-pkg/edsp/edspindexfile.cc

@@ -56,7 +56,7 @@ bool edspIndex::Merge(pkgCacheGenerator &Gen,OpProgress *Prog) const
    pkgCache::PkgFileIterator CFile = Gen.GetCurFile();
    CFile->Size = Pkg.FileSize();
    CFile->mtime = Pkg.ModificationTime();
-   map_ptrloc const storage = Gen.WriteUniqString("edsp::scenario");
+   map_stringitem_t const storage = Gen.StoreString(pkgCacheGenerator::MIXED, "edsp::scenario");
    CFile->Archive = storage;
 
    if (Gen.MergeList(Parser) == false)

+ 2 - 2
apt-pkg/indexcopy.h

@@ -93,8 +93,8 @@ class SigVerify								/*{{{*/
    /** \brief dpointer placeholder (for later in case we need it) */
    void *d;
 
-   bool Verify(std::string prefix,std::string file, indexRecords *records);
-   bool CopyMetaIndex(std::string CDROM, std::string CDName, 
+   APT_HIDDEN bool Verify(std::string prefix,std::string file, indexRecords *records);
+   APT_HIDDEN bool CopyMetaIndex(std::string CDROM, std::string CDName,
 		      std::string prefix, std::string file);
 
  public:

+ 29 - 10
apt-pkg/indexrecords.cc

@@ -37,6 +37,11 @@ APT_PURE string indexRecords::GetSuite() const
    return this->Suite;
 }
 
+APT_PURE bool indexRecords::GetSupportsAcquireByHash() const
+{
+   return this->SupportsAcquireByHash;
+}
+
 APT_PURE bool indexRecords::CheckDist(const string MaybeDist) const
 {
    return (this->Dist == MaybeDist
@@ -86,12 +91,14 @@ bool indexRecords::Load(const string Filename)				/*{{{*/
       strprintf(ErrorText, _("No sections in Release file %s"), Filename.c_str());
       return false;
    }
+   // FIXME: find better tag name
+   SupportsAcquireByHash = Section.FindB("Acquire-By-Hash", false);
 
    Suite = Section.FindS("Suite");
    Dist = Section.FindS("Codename");
 
-   int i;
-   for (i=0;HashString::SupportedHashes()[i] != NULL; i++)
+   bool FoundHashSum = false;
+   for (int i=0;HashString::SupportedHashes()[i] != NULL; i++)
    {
       if (!Section.Find(HashString::SupportedHashes()[i], Start, End))
 	 continue;
@@ -103,16 +110,28 @@ bool indexRecords::Load(const string Filename)				/*{{{*/
       {
 	 if (!parseSumData(Start, End, Name, Hash, Size))
 	    return false;
-	 indexRecords::checkSum *Sum = new indexRecords::checkSum;
-	 Sum->MetaKeyFilename = Name;
-	 Sum->Hashes.push_back(HashString(HashString::SupportedHashes()[i],Hash));
-	 Sum->Size = Size;
-	 Entries[Name] = Sum;
+
+         if (Entries.find(Name) == Entries.end())
+         {
+            indexRecords::checkSum *Sum = new indexRecords::checkSum;
+            Sum->MetaKeyFilename = Name;
+            Sum->Size = Size;
+#if __GNUC__ >= 4
+       #pragma GCC diagnostic push
+       #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+            Sum->Hash = HashString(HashString::SupportedHashes()[i],Hash);
+#if __GNUC__ >= 4
+       #pragma GCC diagnostic pop
+#endif
+            Entries[Name] = Sum;
+         }
+         Entries[Name]->Hashes.push_back(HashString(HashString::SupportedHashes()[i],Hash));
+         FoundHashSum = true;
       }
-      break;
    }
 
-   if(HashString::SupportedHashes()[i] == NULL)
+   if(FoundHashSum == false)
    {
       strprintf(ErrorText, _("No Hash entry in Release file %s"), Filename.c_str());
       return false;
@@ -239,6 +258,6 @@ indexRecords::indexRecords()
 }
 
 indexRecords::indexRecords(const string ExpectedDist) :
-   ExpectedDist(ExpectedDist), ValidUntil(0)
+   ExpectedDist(ExpectedDist), ValidUntil(0), SupportsAcquireByHash(false)
 {
 }

+ 5 - 1
apt-pkg/indexrecords.h

@@ -21,17 +21,20 @@
 
 class indexRecords
 {
-   bool parseSumData(const char *&Start, const char *End, std::string &Name,
+   APT_HIDDEN bool parseSumData(const char *&Start, const char *End, std::string &Name,
 		     std::string &Hash, unsigned long long &Size);
    public:
    struct checkSum;
    std::string ErrorText;
+   // dpointer (for later9
+   void * d;
    
    protected:
    std::string Dist;
    std::string Suite;
    std::string ExpectedDist;
    time_t ValidUntil;
+   bool SupportsAcquireByHash;
 
    std::map<std::string,checkSum *> Entries;
 
@@ -49,6 +52,7 @@ class indexRecords
    virtual bool Load(std::string Filename);
    std::string GetDist() const;
    std::string GetSuite() const;
+   bool GetSupportsAcquireByHash() const;
    time_t GetValidUntil() const;
    virtual bool CheckDist(const std::string MaybeDist) const;
    std::string GetExpectedDist() const;

+ 2 - 0
apt-pkg/install-progress.cc

@@ -21,6 +21,8 @@
 namespace APT {
 namespace Progress {
 
+PackageManager::PackageManager() : d(NULL), percentage(0.0), last_reported_progress(-1) {}
+PackageManager::~PackageManager() {}
 
 /* Return a APT::Progress::PackageManager based on the global
  * apt configuration (i.e. APT::Status-Fd and APT::Status-deb822-Fd)

+ 3 - 4
apt-pkg/install-progress.h

@@ -26,9 +26,8 @@ namespace Progress {
     int last_reported_progress;
 
  public:
-    PackageManager()
-       : percentage(0.0), last_reported_progress(-1) {};
-    virtual ~PackageManager() {};
+    PackageManager();
+    virtual ~PackageManager();
 
     /* Global Start/Stop */
     virtual void Start(int /*child_pty*/=-1) {};
@@ -120,7 +119,7 @@ namespace Progress {
  class PackageManagerFancy : public PackageManager
  {
  private:
-    static void staticSIGWINCH(int);
+    APT_HIDDEN static void staticSIGWINCH(int);
     static std::vector<PackageManagerFancy*> instances;
     APT_HIDDEN bool DrawStatusLine();
 

+ 1 - 1
apt-pkg/metaindex.h

@@ -53,7 +53,7 @@ class metaIndex
 
    metaIndex(std::string const &URI, std::string const &Dist, 
              char const * const Type) 
-      : Indexes(NULL), Type(Type), URI(URI), Dist(Dist)
+      : Indexes(NULL), Type(Type), URI(URI), Dist(Dist), Trusted(false)
    {
       /* nothing */
    }

+ 49 - 2
apt-pkg/packagemanager.cc

@@ -373,6 +373,8 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth)
    std::list<DepIterator> needConfigure;
    do
    {
+      // Check each dependency and see if anything needs to be done
+      // so that it can be configured
       Changed = false;
       for (DepIterator D = instVer.DependsList(); D.end() == false; )
       {
@@ -384,7 +386,8 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth)
 	    continue;
 	 Bad = true;
 
-	 // Check for dependencies that have not been unpacked, probably due to loops.
+         // the first pass checks if we its all good, i.e. if we have
+         // to do anything at all
 	 for (DepIterator Cur = Start; true; ++Cur)
 	 {
 	    SPtrArray<Version *> VList = Cur.AllTargets();
@@ -403,6 +406,47 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth)
 		  break;
 	       }
 
+	       // Check if the version that is going to be installed will satisfy the dependency
+	       if (Cache[DepPkg].InstallVer != *I || List->IsNow(DepPkg) == false)
+		  continue;
+
+	       if (PkgLoop == true)
+	       {
+		  if (Debug)
+		     std::clog << OutputInDepth(Depth) << "Package " << Pkg << " loops in SmartConfigure" << std::endl;
+	          Bad = false;
+	       }
+	    }
+
+            if (Cur == End || Bad == false)
+	       break;
+         }
+
+         // this dependency is in a good state, so we can stop
+         if (Bad == false)
+         {
+            if (Debug)
+               std::clog << OutputInDepth(Depth) << "Found ok dep " << D.TargetPkg() << std::endl;
+            continue;
+         }
+
+	 // Check for dependencies that have not been unpacked, 
+         // probably due to loops.
+	 for (DepIterator Cur = Start; true; ++Cur)
+	 {
+	    SPtrArray<Version *> VList = Cur.AllTargets();
+
+	    for (Version **I = VList; *I != 0; ++I)
+	    {
+	       VerIterator Ver(Cache,*I);
+	       PkgIterator DepPkg = Ver.ParentPkg();
+
+	       // Check if the current version of the package is available and will satisfy this dependency
+	       if (DepPkg.CurrentVer() == Ver && List->IsNow(DepPkg) == true &&
+		   List->IsFlag(DepPkg,pkgOrderList::Removed) == false &&
+		   DepPkg.State() == PkgIterator::NeedsNothing)
+                  continue;
+
 	       // Check if the version that is going to be installed will satisfy the dependency
 	       if (Cache[DepPkg].InstallVer != *I || List->IsNow(DepPkg) == false)
 		  continue;
@@ -420,6 +464,8 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth)
 		  if (NonLoopingSmart(UNPACK_IMMEDIATE, Pkg, DepPkg, Depth, PkgLoop, &Bad, &Changed) == false)
 		     return false;
 	       }
+               // at this point we either unpacked a Dep or we are in a loop,
+               // no need to unpack a second one
 	       break;
 	    }
 
@@ -436,6 +482,7 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth)
          return _error->Error("Internal error: MaxLoopCount reached in SmartUnPack (1) for %s, aborting", Pkg.FullName().c_str());
    } while (Changed == true);
 
+   // now go over anything that needs configuring
    Bad = false, Changed = false, i = 0;
    do
    {
@@ -1033,7 +1080,7 @@ pkgPackageManager::DoInstallPostFork(APT::Progress::PackageManager *progress)
       return Failed;
    
    return Res;
-};
+}
 #else
 pkgPackageManager::OrderResult
 pkgPackageManager::DoInstallPostFork(int statusFd)

+ 3 - 2
apt-pkg/packagemanager.h

@@ -47,8 +47,8 @@ class pkgRecords;
 namespace APT {
    namespace Progress {
       class PackageManager;
-   };
-};
+   }
+}
 
 
 class pkgPackageManager : protected pkgCache::Namespace
@@ -98,6 +98,7 @@ class pkgPackageManager : protected pkgCache::Namespace
    virtual bool Remove(PkgIterator /*Pkg*/,bool /*Purge*/=false) {return false;};
 #if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 13)
    virtual bool Go(APT::Progress::PackageManager * /*progress*/) {return true;};
+   virtual bool Go(int /*statusFd*/=-1) {return true;};
 #else
    virtual bool Go(int /*statusFd*/=-1) {return true;};
 #endif

+ 34 - 41
apt-pkg/pkgcache.cc

@@ -54,12 +54,8 @@ pkgCache::Header::Header()
    
    /* Whenever the structures change the major version should be bumped,
       whenever the generator changes the minor version should be bumped. */
-   MajorVersion = 9;
-#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 13)
-   MinorVersion = 2;
-#else
-   MinorVersion = 1;
-#endif
+   MajorVersion = 10;
+   MinorVersion = 0;
    Dirty = false;
    
    HeaderSz = sizeof(pkgCache::Header);
@@ -86,11 +82,10 @@ pkgCache::Header::Header()
    MaxDescFileSize = 0;
    
    FileList = 0;
-   StringList = 0;
    VerSysName = 0;
    Architecture = 0;
-   memset(PkgHashTable,0,sizeof(PkgHashTable));
-   memset(GrpHashTable,0,sizeof(GrpHashTable));
+   Architectures = 0;
+   HashTableSize = _config->FindI("APT::Cache-HashTableSize", 10 * 1048);
    memset(Pools,0,sizeof(Pools));
 
    CacheFileSize = 0;
@@ -145,7 +140,6 @@ bool pkgCache::ReMap(bool const &Errorchecks)
    DescP = (Description *)Map.Data();
    ProvideP = (Provides *)Map.Data();
    DepP = (Dependency *)Map.Data();
-   StringItemP = (StringItem *)Map.Data();
    StrP = (char *)Map.Data();
 
    if (Errorchecks == false)
@@ -193,20 +187,20 @@ bool pkgCache::ReMap(bool const &Errorchecks)
 /* This is used to generate the hash entries for the HashTable. With my
    package list from bo this function gets 94% table usage on a 512 item
    table (480 used items) */
-unsigned long pkgCache::sHash(const string &Str) const
+map_id_t pkgCache::sHash(const string &Str) const
 {
    unsigned long Hash = 0;
    for (string::const_iterator I = Str.begin(); I != Str.end(); ++I)
       Hash = 41 * Hash + tolower_ascii(*I);
-   return Hash % _count(HeaderP->PkgHashTable);
+   return Hash % HeaderP->HashTableSize;
 }
 
-unsigned long pkgCache::sHash(const char *Str) const
+map_id_t pkgCache::sHash(const char *Str) const
 {
    unsigned long Hash = tolower_ascii(*Str);
    for (const char *I = Str + 1; *I != 0; ++I)
       Hash = 41 * Hash + tolower_ascii(*I);
-   return Hash % _count(HeaderP->PkgHashTable);
+   return Hash % HeaderP->HashTableSize;
 }
 									/*}}}*/
 // Cache::SingleArchFindPkg - Locate a package by name			/*{{{*/
@@ -217,13 +211,10 @@ unsigned long pkgCache::sHash(const char *Str) const
 pkgCache::PkgIterator pkgCache::SingleArchFindPkg(const string &Name)
 {
    // Look at the hash bucket
-   Package *Pkg = PkgP + HeaderP->PkgHashTable[Hash(Name)];
-   for (; Pkg != PkgP; Pkg = PkgP + Pkg->NextPackage)
+   Package *Pkg = PkgP + HeaderP->PkgHashTable()[Hash(Name)];
+   for (; Pkg != PkgP; Pkg = PkgP + Pkg->Next)
    {
-      if (unlikely(Pkg->Name == 0))
-	 continue;
-
-      int const cmp = strcasecmp(Name.c_str(), StrP + Pkg->Name);
+      int const cmp = strcmp(Name.c_str(), StrP + (GrpP + Pkg->Group)->Name);
       if (cmp == 0)
 	 return PkgIterator(*this, Pkg);
       else if (cmp < 0)
@@ -282,12 +273,9 @@ pkgCache::GrpIterator pkgCache::FindGrp(const string &Name) {
 		return GrpIterator(*this,0);
 
 	// Look at the hash bucket for the group
-	Group *Grp = GrpP + HeaderP->GrpHashTable[sHash(Name)];
+	Group *Grp = GrpP + HeaderP->GrpHashTable()[sHash(Name)];
 	for (; Grp != GrpP; Grp = GrpP + Grp->Next) {
-		if (unlikely(Grp->Name == 0))
-		   continue;
-
-		int const cmp = strcasecmp(Name.c_str(), StrP + Grp->Name);
+		int const cmp = strcmp(Name.c_str(), StrP + Grp->Name);
 		if (cmp == 0)
 			return GrpIterator(*this, Grp);
 		else if (cmp < 0)
@@ -364,19 +352,15 @@ pkgCache::PkgIterator pkgCache::GrpIterator::FindPkg(string Arch) const {
 	   last one we check, so we do it now. */
 	if (Arch == "native" || Arch == myArch || Arch == "all") {
 		pkgCache::Package *Pkg = Owner->PkgP + S->LastPackage;
-		if (strcasecmp(myArch, Owner->StrP + Pkg->Arch) == 0)
+		if (strcmp(myArch, Owner->StrP + Pkg->Arch) == 0)
 			return PkgIterator(*Owner, Pkg);
 		Arch = myArch;
 	}
 
-	/* Iterate over the list to find the matching arch
-	   unfortunately this list includes "package noise"
-	   (= different packages with same calculated hash),
-	   so we need to check the name also */
+	// Iterate over the list to find the matching arch
 	for (pkgCache::Package *Pkg = PackageList(); Pkg != Owner->PkgP;
-	     Pkg = Owner->PkgP + Pkg->NextPackage) {
-		if (S->Name == Pkg->Name &&
-		    stringcasecmp(Arch, Owner->StrP + Pkg->Arch) == 0)
+	     Pkg = Owner->PkgP + Pkg->Next) {
+		if (stringcmp(Arch, Owner->StrP + Pkg->Arch) == 0)
 			return PkgIterator(*Owner, Pkg);
 		if ((Owner->PkgP + S->LastPackage) == Pkg)
 			break;
@@ -423,7 +407,7 @@ pkgCache::PkgIterator pkgCache::GrpIterator::NextPkg(pkgCache::PkgIterator const
 	if (S->LastPackage == LastPkg.Index())
 		return PkgIterator(*Owner, 0);
 
-	return PkgIterator(*Owner, Owner->PkgP + LastPkg->NextPackage);
+	return PkgIterator(*Owner, Owner->PkgP + LastPkg->Next);
 }
 									/*}}}*/
 // GrpIterator::operator ++ - Postfix incr				/*{{{*/
@@ -436,10 +420,10 @@ void pkgCache::GrpIterator::operator ++(int)
       S = Owner->GrpP + S->Next;
 
    // Follow the hash table
-   while (S == Owner->GrpP && (HashIndex+1) < (signed)_count(Owner->HeaderP->GrpHashTable))
+   while (S == Owner->GrpP && (HashIndex+1) < (signed)Owner->HeaderP->HashTableSize)
    {
       HashIndex++;
-      S = Owner->GrpP + Owner->HeaderP->GrpHashTable[HashIndex];
+      S = Owner->GrpP + Owner->HeaderP->GrpHashTable()[HashIndex];
    }
 }
 									/*}}}*/
@@ -450,13 +434,13 @@ void pkgCache::PkgIterator::operator ++(int)
 {
    // Follow the current links
    if (S != Owner->PkgP)
-      S = Owner->PkgP + S->NextPackage;
+      S = Owner->PkgP + S->Next;
 
    // Follow the hash table
-   while (S == Owner->PkgP && (HashIndex+1) < (signed)_count(Owner->HeaderP->PkgHashTable))
+   while (S == Owner->PkgP && (HashIndex+1) < (signed)Owner->HeaderP->HashTableSize)
    {
       HashIndex++;
-      S = Owner->PkgP + Owner->HeaderP->PkgHashTable[HashIndex];
+      S = Owner->PkgP + Owner->HeaderP->PkgHashTable()[HashIndex];
    }
 }
 									/*}}}*/
@@ -532,7 +516,10 @@ operator<<(std::ostream& out, pkgCache::PkgIterator Pkg)
       out << " -> " << candidate;
    if ( newest != "none" && candidate != newest)
       out << " | " << newest;
-   out << " > ( " << string(Pkg.Section()==0?"none":Pkg.Section()) << " )";
+   if (Pkg->VersionList == 0)
+      out << " > ( none )";
+   else
+      out << " > ( " << string(Pkg.VersionList().Section()==0?"unknown":Pkg.VersionList().Section()) << " )";
    return out;
 }
 									/*}}}*/
@@ -1039,8 +1026,14 @@ bool pkgCache::PrvIterator::IsMultiArchImplicit() const
 {
    pkgCache::PkgIterator const Owner = OwnerPkg();
    pkgCache::PkgIterator const Parent = ParentPkg();
-   if (strcmp(Owner.Arch(), Parent.Arch()) != 0 || Owner->Name == Parent->Name)
+   if (strcmp(Owner.Arch(), Parent.Arch()) != 0 || Owner.Group()->Name == Parent.Group()->Name)
       return true;
    return false;
 }
 									/*}}}*/
+APT_DEPRECATED APT_PURE const char * pkgCache::PkgIterator::Section() const {/*{{{*/
+   if (S->VersionList == 0)
+      return 0;
+   return VersionList().Section();
+}
+									/*}}}*/

+ 112 - 122
apt-pkg/pkgcache.h

@@ -79,11 +79,23 @@
 
 #include <string>
 #include <time.h>
+#include <stdint.h>
 
 #ifndef APT_8_CLEANER_HEADERS
 using std::string;
 #endif
 
+// storing file sizes of indexes, which are way below 4 GB for now
+typedef uint32_t map_filesize_t;
+// each package/group/dependency gets an id
+typedef uint32_t map_id_t;
+// some files get an id, too, but in far less absolute numbers
+typedef uint16_t map_fileid_t;
+// relative pointer from cache start
+typedef uint32_t map_pointer_t;
+// same as the previous, but documented to be to a string item
+typedef map_pointer_t map_stringitem_t;
+
 class pkgVersioningSystem;
 class pkgCache								/*{{{*/
 {
@@ -97,7 +109,6 @@ class pkgCache								/*{{{*/
    struct Description;
    struct Provides;
    struct Dependency;
-   struct StringItem;
    struct VerFile;
    struct DescFile;
    
@@ -158,8 +169,8 @@ class pkgCache								/*{{{*/
    std::string CacheFile;
    MMap &Map;
 
-   unsigned long sHash(const std::string &S) const APT_PURE;
-   unsigned long sHash(const char *S) const APT_PURE;
+   map_id_t sHash(const std::string &S) const APT_PURE;
+   map_id_t sHash(const char *S) const APT_PURE;
    
    public:
    
@@ -174,7 +185,6 @@ class pkgCache								/*{{{*/
    Description *DescP;
    Provides *ProvideP;
    Dependency *DepP;
-   StringItem *StringItemP;
    char *StrP;
 
    virtual bool ReMap(bool const &Errorchecks = true);
@@ -183,8 +193,8 @@ class pkgCache								/*{{{*/
    inline void *DataEnd() {return ((unsigned char *)Map.Data()) + Map.Size();}
       
    // String hashing function (512 range)
-   inline unsigned long Hash(const std::string &S) const {return sHash(S);}
-   inline unsigned long Hash(const char *S) const {return sHash(S);}
+   inline map_id_t Hash(const std::string &S) const {return sHash(S);}
+   inline map_id_t Hash(const char *S) const {return sHash(S);}
 
    // Useful transformation things
    const char *Priority(unsigned char Priority);
@@ -218,7 +228,7 @@ class pkgCache								/*{{{*/
 
 private:
    bool MultiArchEnabled;
-   PkgIterator SingleArchFindPkg(const std::string &Name);
+   APT_HIDDEN PkgIterator SingleArchFindPkg(const std::string &Name);
 };
 									/*}}}*/
 // Header structure							/*{{{*/
@@ -263,37 +273,31 @@ struct pkgCache::Header
        These indicate the number of each structure contained in the cache.
        PackageCount is especially useful for generating user state structures.
        See Package::Id for more info. */
-   unsigned long GroupCount;
-   unsigned long PackageCount;
-   unsigned long VersionCount;
-   unsigned long DescriptionCount;
-   unsigned long DependsCount;
-   unsigned long PackageFileCount;
-   unsigned long VerFileCount;
-   unsigned long DescFileCount;
-   unsigned long ProvidesCount;
+   map_id_t GroupCount;
+   map_id_t PackageCount;
+   map_id_t VersionCount;
+   map_id_t DescriptionCount;
+   map_id_t DependsCount;
+   map_fileid_t PackageFileCount;
+   map_fileid_t VerFileCount;
+   map_fileid_t DescFileCount;
+   map_id_t ProvidesCount;
 
    /** \brief index of the first PackageFile structure
 
        The PackageFile structures are singly linked lists that represent
        all package files that have been merged into the cache. */
-   map_ptrloc FileList;
-   /** \brief index of the first StringItem structure
-
-       The cache contains a list of all the unique strings (StringItems).
-       The parser reads this list into memory so it can match strings
-       against it.*/
-   map_ptrloc StringList;
+   map_pointer_t FileList;
    /** \brief String representing the version system used */
-   map_ptrloc VerSysName;
+   map_pointer_t VerSysName;
    /** \brief native architecture the cache was built against */
-   map_ptrloc Architecture;
+   map_pointer_t Architecture;
    /** \brief all architectures the cache was built against */
-   map_ptrloc Architectures;
+   map_pointer_t Architectures;
    /** \brief The maximum size of a raw entry from the original Package file */
-   unsigned long MaxVerFileSize;
+   map_filesize_t MaxVerFileSize;
    /** \brief The maximum size of a raw entry from the original Translation file */
-   unsigned long MaxDescFileSize;
+   map_filesize_t MaxDescFileSize;
 
    /** \brief The Pool structures manage the allocation pools that the generator uses
 
@@ -304,23 +308,23 @@ struct pkgCache::Header
        stores this information so future additions can make use of any unused pool
        blocks. */
    DynamicMMap::Pool Pools[9];
-   
+
    /** \brief hash tables providing rapid group/package name lookup
 
-       Each group/package name is inserted into the hash table using pkgCache::Hash(const &string)
+       Each group/package name is inserted into a hash table using pkgCache::Hash(const &string)
        By iterating over each entry in the hash table it is possible to iterate over
        the entire list of packages. Hash Collisions are handled with a singly linked
        list of packages based at the hash item. The linked list contains only
        packages that match the hashing function.
        In the PkgHashTable is it possible that multiple packages have the same name -
        these packages are stored as a sequence in the list.
-
-       Beware: The Hashmethod assumes that the hash table sizes are equal */
-   map_ptrloc PkgHashTable[2*1048];
-   map_ptrloc GrpHashTable[2*1048];
+       The size of both tables is the same. */
+   unsigned int HashTableSize;
+   map_pointer_t * PkgHashTable() const { return (map_pointer_t*) (this + 1); }
+   map_pointer_t * GrpHashTable() const { return PkgHashTable() + HashTableSize; }
 
    /** \brief Size of the complete cache file */
-   unsigned long  CacheFileSize;
+   unsigned long long CacheFileSize;
 
    bool CheckSizes(Header &Against) const APT_PURE;
    Header();
@@ -336,17 +340,17 @@ struct pkgCache::Header
 struct pkgCache::Group
 {
    /** \brief Name of the group */
-   map_ptrloc Name;		// StringItem
+   map_stringitem_t Name;
 
    // Linked List
    /** \brief Link to the first package which belongs to the group */
-   map_ptrloc FirstPackage;	// Package
+   map_pointer_t FirstPackage;	// Package
    /** \brief Link to the last package which belongs to the group */
-   map_ptrloc LastPackage;	// Package
+   map_pointer_t LastPackage;	// Package
    /** \brief Link to the next Group */
-   map_ptrloc Next;		// Group
+   map_pointer_t Next;		// Group
    /** \brief unique sequel ID */
-   unsigned int ID;
+   map_id_t ID;
 
 };
 									/*}}}*/
@@ -364,10 +368,13 @@ struct pkgCache::Group
 */
 struct pkgCache::Package
 {
-   /** \brief Name of the package */
-   map_ptrloc Name;              // StringItem
+   /** \brief Name of the package
+    * Note that the access method Name() will remain. It is just this data member
+    * deprecated as this information is already stored and available via the
+    * associated Group – so it is wasting precious binary cache space */
+   APT_DEPRECATED map_stringitem_t Name;
    /** \brief Architecture of the package */
-   map_ptrloc Arch;              // StringItem
+   map_stringitem_t Arch;
    /** \brief Base of a singly linked list of versions
 
        Each structure represents a unique version of the package.
@@ -377,24 +384,19 @@ struct pkgCache::Package
        versions of a package can be cleanly handled by the system.
        Furthermore, this linked list is guaranteed to be sorted
        from Highest version to lowest version with no duplicate entries. */
-   map_ptrloc VersionList;       // Version
+   map_pointer_t VersionList;       // Version
    /** \brief index to the installed version */
-   map_ptrloc CurrentVer;        // Version
-   /** \brief indicates the deduced section
-
-       Should be the index to the string "Unknown" or to the section
-       of the last parsed item. */
-   map_ptrloc Section;           // StringItem
+   map_pointer_t CurrentVer;        // Version
    /** \brief index of the group this package belongs to */
-   map_ptrloc Group;             // Group the Package belongs to
+   map_pointer_t Group;             // Group the Package belongs to
 
    // Linked list
    /** \brief Link to the next package in the same bucket */
-   map_ptrloc NextPackage;       // Package
+   map_pointer_t Next;       // Package
    /** \brief List of all dependencies on this package */
-   map_ptrloc RevDepends;        // Dependency
+   map_pointer_t RevDepends;        // Dependency
    /** \brief List of all "packages" this package provide */
-   map_ptrloc ProvidesList;      // Provides
+   map_pointer_t ProvidesList;      // Provides
 
    // Install/Remove/Purge etc
    /** \brief state that the user wishes the package to be in */
@@ -414,7 +416,7 @@ struct pkgCache::Package
        This allows clients to create an array of size PackageCount and use it to store
        state information for the package map. For instance the status file emitter uses
        this to track which packages have been emitted already. */
-   unsigned int ID;
+   map_id_t ID;
    /** \brief some useful indicators of the package's state */
    unsigned long Flags;
 };
@@ -428,30 +430,30 @@ struct pkgCache::Package
 struct pkgCache::PackageFile
 {
    /** \brief physical disk file that this PackageFile represents */
-   map_ptrloc FileName;        // StringItem
+   map_stringitem_t FileName;
    /** \brief the release information
 
        Please see the files document for a description of what the
        release information means. */
-   map_ptrloc Archive;         // StringItem
-   map_ptrloc Codename;        // StringItem
-   map_ptrloc Component;       // StringItem
-   map_ptrloc Version;         // StringItem
-   map_ptrloc Origin;          // StringItem
-   map_ptrloc Label;           // StringItem
-   map_ptrloc Architecture;    // StringItem
+   map_stringitem_t Archive;
+   map_stringitem_t Codename;
+   map_stringitem_t Component;
+   map_stringitem_t Version;
+   map_stringitem_t Origin;
+   map_stringitem_t Label;
+   map_stringitem_t Architecture;
    /** \brief The site the index file was fetched from */
-   map_ptrloc Site;            // StringItem
+   map_stringitem_t Site;
    /** \brief indicates what sort of index file this is
 
        @TODO enumerate at least the possible indexes */
-   map_ptrloc IndexType;       // StringItem
+   map_stringitem_t IndexType;
    /** \brief Size of the file
 
        Used together with the modification time as a
        simple check to ensure that the Packages
        file has not been altered since Cache generation. */
-   unsigned long Size;
+   map_filesize_t Size;
    /** \brief Modification time for the file */
    time_t mtime;
 
@@ -460,9 +462,9 @@ struct pkgCache::PackageFile
 
    // Linked list
    /** \brief Link to the next PackageFile in the Cache */
-   map_ptrloc NextFile;        // PackageFile
+   map_pointer_t NextFile;        // PackageFile
    /** \brief unique sequel ID */
-   unsigned int ID;
+   map_fileid_t ID;
 };
 									/*}}}*/
 // VerFile structure							/*{{{*/
@@ -473,13 +475,13 @@ struct pkgCache::PackageFile
 struct pkgCache::VerFile
 {
    /** \brief index of the package file that this version was found in */
-   map_ptrloc File;           // PackageFile
+   map_pointer_t File;           // PackageFile
    /** \brief next step in the linked list */
-   map_ptrloc NextFile;       // PkgVerFile
+   map_pointer_t NextFile;       // PkgVerFile
    /** \brief position in the package file */
-   map_ptrloc Offset;         // File offset
+   map_filesize_t Offset;         // File offset
    /** @TODO document pkgCache::VerFile::Size */
-   unsigned long Size;
+   map_filesize_t Size;
 };
 									/*}}}*/
 // DescFile structure							/*{{{*/
@@ -487,13 +489,13 @@ struct pkgCache::VerFile
 struct pkgCache::DescFile
 {
    /** \brief index of the file that this description was found in */
-   map_ptrloc File;           // PackageFile
+   map_pointer_t File;           // PackageFile
    /** \brief next step in the linked list */
-   map_ptrloc NextFile;       // PkgVerFile
+   map_pointer_t NextFile;       // PkgVerFile
    /** \brief position in the file */
-   map_ptrloc Offset;         // File offset
+   map_filesize_t Offset;         // File offset
    /** @TODO document pkgCache::DescFile::Size */
-   unsigned long Size;
+   map_filesize_t Size;
 };
 									/*}}}*/
 // Version structure							/*{{{*/
@@ -505,9 +507,15 @@ struct pkgCache::DescFile
 struct pkgCache::Version
 {
    /** \brief complete version string */
-   map_ptrloc VerStr;            // StringItem
+   map_stringitem_t VerStr;
    /** \brief section this version is filled in */
-   map_ptrloc Section;           // StringItem
+   map_stringitem_t Section;
+   /** \brief source package name this version comes from
+      Always contains the name, even if it is the same as the binary name */
+   map_stringitem_t SourcePkgName;
+   /** \brief source version this version comes from
+      Always contains the version string, even if it is the same as the binary version */
+   map_stringitem_t SourceVerStr;
 
    /** \brief Multi-Arch capabilities of a package version */
    enum VerMultiArch { None = 0, /*!< is the default and doesn't trigger special behaviour */
@@ -529,33 +537,33 @@ struct pkgCache::Version
        applies to. If FileList is 0 then this is a blank version.
        The structure should also have a 0 in all other fields excluding
        pkgCache::Version::VerStr and Possibly pkgCache::Version::NextVer. */
-   map_ptrloc FileList;          // VerFile
+   map_pointer_t FileList;          // VerFile
    /** \brief next (lower or equal) version in the linked list */
-   map_ptrloc NextVer;           // Version
+   map_pointer_t NextVer;           // Version
    /** \brief next description in the linked list */
-   map_ptrloc DescriptionList;   // Description
+   map_pointer_t DescriptionList;   // Description
    /** \brief base of the dependency list */
-   map_ptrloc DependsList;       // Dependency
+   map_pointer_t DependsList;       // Dependency
    /** \brief links to the owning package
 
        This allows reverse dependencies to determine the package */
-   map_ptrloc ParentPkg;         // Package
+   map_pointer_t ParentPkg;         // Package
    /** \brief list of pkgCache::Provides */
-   map_ptrloc ProvidesList;      // Provides
+   map_pointer_t ProvidesList;      // Provides
 
    /** \brief archive size for this version
 
        For Debian this is the size of the .deb file. */
-   unsigned long long Size;      // These are the .deb size
+   uint64_t Size; // These are the .deb size
    /** \brief uncompressed size for this version */
-   unsigned long long InstalledSize;
+   uint64_t InstalledSize;
    /** \brief characteristic value representing this version
 
        No two packages in existence should have the same VerStr
        and Hash with different contents. */
    unsigned short Hash;
    /** \brief unique sequel ID */
-   unsigned int ID;
+   map_id_t ID;
    /** \brief parsed priority value */
    unsigned char Priority;
 };
@@ -568,22 +576,22 @@ struct pkgCache::Description
 
        If the value has a 0 length then this is read using the Package
        file else the Translation-CODE file is used. */
-   map_ptrloc language_code;     // StringItem
+   map_stringitem_t language_code;
    /** \brief MD5sum of the original description
 
        Used to map Translations of a description to a version
        and to check that the Translation is up-to-date. */
-   map_ptrloc md5sum;            // StringItem
+   map_stringitem_t md5sum;
 
    /** @TODO document pkgCache::Description::FileList */
-   map_ptrloc FileList;          // DescFile
+   map_pointer_t FileList;          // DescFile
    /** \brief next translation for this description */
-   map_ptrloc NextDesc;          // Description
+   map_pointer_t NextDesc;          // Description
    /** \brief the text is a description of this package */
-   map_ptrloc ParentPkg;         // Package
+   map_pointer_t ParentPkg;         // Package
 
    /** \brief unique sequel ID */
-   unsigned int ID;
+   map_id_t ID;
 };
 									/*}}}*/
 // Dependency structure							/*{{{*/
@@ -596,21 +604,21 @@ struct pkgCache::Description
 struct pkgCache::Dependency
 {
    /** \brief string of the version the dependency is applied against */
-   map_ptrloc Version;         // StringItem
+   map_stringitem_t Version;
    /** \brief index of the package this depends applies to
 
        The generator will - if the package does not already exist -
        create a blank (no version records) package. */
-   map_ptrloc Package;         // Package
+   map_pointer_t Package;         // Package
    /** \brief next dependency of this version */
-   map_ptrloc NextDepends;     // Dependency
+   map_pointer_t NextDepends;     // Dependency
    /** \brief next reverse dependency of this package */
-   map_ptrloc NextRevDepends;  // Dependency
+   map_pointer_t NextRevDepends;  // Dependency
    /** \brief version of the package which has the reverse depends */
-   map_ptrloc ParentVer;       // Version
+   map_pointer_t ParentVer;       // Version
 
    /** \brief unique sequel ID */
-   map_ptrloc ID;
+   map_id_t ID;
    /** \brief Dependency type - Depends, Recommends, Conflicts, etc */
    unsigned char Type;
    /** \brief comparison operator specified on the depends line
@@ -631,39 +639,21 @@ struct pkgCache::Dependency
 struct pkgCache::Provides
 {
    /** \brief index of the package providing this */
-   map_ptrloc ParentPkg;        // Package
+   map_pointer_t ParentPkg;        // Package
    /** \brief index of the version this provide line applies to */
-   map_ptrloc Version;          // Version
+   map_pointer_t Version;          // Version
    /** \brief version in the provides line (if any)
 
        This version allows dependencies to depend on specific versions of a
        Provides, as well as allowing Provides to override existing packages.
        This is experimental. Note that Debian doesn't allow versioned provides */
-   map_ptrloc ProvideVersion;   // StringItem
+   map_stringitem_t ProvideVersion;
    /** \brief next provides (based of package) */
-   map_ptrloc NextProvides;     // Provides
+   map_pointer_t NextProvides;     // Provides
    /** \brief next provides (based of version) */
-   map_ptrloc NextPkgProv;      // Provides
+   map_pointer_t NextPkgProv;      // Provides
 };
 									/*}}}*/
-// StringItem structure							/*{{{*/
-/** \brief used for generating single instances of strings
-
-    Some things like Section Name are are useful to have as unique tags.
-    It is part of a linked list based at pkgCache::Header::StringList
-
-    All strings are simply inlined any place in the file that is natural
-    for the writer. The client should make no assumptions about the positioning
-    of strings. All StringItems should be null-terminated. */
-struct pkgCache::StringItem
-{
-   /** \brief string this refers to */
-   map_ptrloc String;        // StringItem
-   /** \brief Next link in the chain */
-   map_ptrloc NextItem;      // StringItem
-};
-									/*}}}*/
-
 
 inline char const * pkgCache::NativeArch()
 	{ return StrP + HeaderP->Architecture; }

+ 115 - 140
apt-pkg/pkgcachegen.cc

@@ -57,8 +57,7 @@ pkgCacheGenerator::pkgCacheGenerator(DynamicMMap *pMap,OpProgress *Prog) :
 		    FoundFileDeps(0)
 {
    CurrentFile = 0;
-   memset(UniqHash,0,sizeof(UniqHash));
-   
+
    if (_error->PendingError() == true)
       return;
 
@@ -73,13 +72,16 @@ pkgCacheGenerator::pkgCacheGenerator(DynamicMMap *pMap,OpProgress *Prog) :
 
       // Starting header
       *Cache.HeaderP = pkgCache::Header();
-      map_ptrloc const idxVerSysName = WriteStringInMap(_system->VS->Label);
+
+      // make room for the hashtables for packages and groups
+      if (Map.RawAllocate(2 * (Cache.HeaderP->HashTableSize * sizeof(map_pointer_t))) == 0)
+	 return;
+
+      map_stringitem_t const idxVerSysName = WriteStringInMap(_system->VS->Label);
       if (unlikely(idxVerSysName == 0))
 	 return;
       Cache.HeaderP->VerSysName = idxVerSysName;
-      // this pointer is set in ReMap, but we need it now for WriteUniqString
-      Cache.StringItemP = (pkgCache::StringItem *)Map.Data();
-      map_ptrloc const idxArchitecture = WriteUniqString(_config->Find("APT::Architecture"));
+      map_stringitem_t const idxArchitecture = StoreString(MIXED, _config->Find("APT::Architecture"));
       if (unlikely(idxArchitecture == 0))
 	 return;
       Cache.HeaderP->Architecture = idxArchitecture;
@@ -91,7 +93,7 @@ pkgCacheGenerator::pkgCacheGenerator(DynamicMMap *pMap,OpProgress *Prog) :
 	 std::string list = *a;
 	 for (++a; a != archs.end(); ++a)
 	    list.append(",").append(*a);
-	 map_ptrloc const idxArchitectures = WriteStringInMap(list);
+	 map_stringitem_t const idxArchitectures = WriteStringInMap(list);
 	 if (unlikely(idxArchitectures == 0))
 	    return;
 	 Cache.HeaderP->Architectures = idxArchitectures;
@@ -110,9 +112,9 @@ pkgCacheGenerator::pkgCacheGenerator(DynamicMMap *pMap,OpProgress *Prog) :
       {
 	 _error->Error(_("Cache has an incompatible versioning system"));
 	 return;
-      }      
+      }
    }
-   
+
    Cache.HeaderP->Dirty = true;
    Map.Sync(0,sizeof(pkgCache::Header));
 }
@@ -144,10 +146,6 @@ void pkgCacheGenerator::ReMap(void const * const oldMap, void const * const newM
 
    CurrentFile += (pkgCache::PackageFile const * const) newMap - (pkgCache::PackageFile const * const) oldMap;
 
-   for (size_t i = 0; i < _count(UniqHash); ++i)
-      if (UniqHash[i] != 0)
-	 UniqHash[i] += (pkgCache::StringItem const * const) newMap - (pkgCache::StringItem const * const) oldMap;
-
    for (std::vector<pkgCache::GrpIterator*>::const_iterator i = Dynamic<pkgCache::GrpIterator>::toReMap.begin();
 	i != Dynamic<pkgCache::GrpIterator>::toReMap.end(); ++i)
       (*i)->ReMap(oldMap, newMap);
@@ -171,27 +169,27 @@ void pkgCacheGenerator::ReMap(void const * const oldMap, void const * const newM
       (*i)->ReMap(oldMap, newMap);
 }									/*}}}*/
 // CacheGenerator::WriteStringInMap					/*{{{*/
-map_ptrloc pkgCacheGenerator::WriteStringInMap(const char *String,
+map_stringitem_t pkgCacheGenerator::WriteStringInMap(const char *String,
 					const unsigned long &Len) {
    void const * const oldMap = Map.Data();
-   map_ptrloc const index = Map.WriteString(String, Len);
+   map_stringitem_t const index = Map.WriteString(String, Len);
    if (index != 0)
       ReMap(oldMap, Map.Data());
    return index;
 }
 									/*}}}*/
 // CacheGenerator::WriteStringInMap					/*{{{*/
-map_ptrloc pkgCacheGenerator::WriteStringInMap(const char *String) {
+map_stringitem_t pkgCacheGenerator::WriteStringInMap(const char *String) {
    void const * const oldMap = Map.Data();
-   map_ptrloc const index = Map.WriteString(String);
+   map_stringitem_t const index = Map.WriteString(String);
    if (index != 0)
       ReMap(oldMap, Map.Data());
    return index;
 }
 									/*}}}*/
-map_ptrloc pkgCacheGenerator::AllocateInMap(const unsigned long &size) {/*{{{*/
+map_pointer_t pkgCacheGenerator::AllocateInMap(const unsigned long &size) {/*{{{*/
    void const * const oldMap = Map.Data();
-   map_ptrloc const index = Map.Allocate(size);
+   map_pointer_t const index = Map.Allocate(size);
    if (index != 0)
       ReMap(oldMap, Map.Data());
    return index;
@@ -271,16 +269,16 @@ bool pkgCacheGenerator::MergeList(ListParser &List,
       }
    }
 
-   if (Cache.HeaderP->PackageCount >= (1ULL<<sizeof(Cache.PkgP->ID)*8)-1)
+   if (Cache.HeaderP->PackageCount >= std::numeric_limits<map_id_t>::max())
       return _error->Error(_("Wow, you exceeded the number of package "
 			     "names this APT is capable of."));
-   if (Cache.HeaderP->VersionCount >= (1ULL<<(sizeof(Cache.VerP->ID)*8))-1)
+   if (Cache.HeaderP->VersionCount >= std::numeric_limits<map_id_t>::max())
       return _error->Error(_("Wow, you exceeded the number of versions "
 			     "this APT is capable of."));
-   if (Cache.HeaderP->DescriptionCount >= (1ULL<<(sizeof(Cache.DescP->ID)*8))-1)
+   if (Cache.HeaderP->DescriptionCount >= std::numeric_limits<map_id_t>::max())
       return _error->Error(_("Wow, you exceeded the number of descriptions "
 			     "this APT is capable of."));
-   if (Cache.HeaderP->DependsCount >= (1ULL<<(sizeof(Cache.DepP->ID)*8))-1ULL)
+   if (Cache.HeaderP->DependsCount >= std::numeric_limits<map_id_t>::max())
       return _error->Error(_("Wow, you exceeded the number of dependencies "
 			     "this APT is capable of."));
 
@@ -331,7 +329,7 @@ bool pkgCacheGenerator::MergeListPackage(ListParser &List, pkgCache::PkgIterator
       if (VerDesc.end() == true || MD5SumValue(VerDesc.md5()) != CurMd5)
 	 continue;
 
-      map_ptrloc md5idx = VerDesc->md5sum;
+      map_stringitem_t md5idx = VerDesc->md5sum;
       for (std::vector<std::string>::const_iterator CurLang = availDesc.begin(); CurLang != availDesc.end(); ++CurLang)
       {
 	 // don't add a new description if we have one for the given
@@ -355,7 +353,7 @@ bool pkgCacheGenerator::MergeListVersion(ListParser &List, pkgCache::PkgIterator
 {
    pkgCache::VerIterator Ver = Pkg.VersionList();
    Dynamic<pkgCache::VerIterator> DynVer(Ver);
-   map_ptrloc *LastVer = &Pkg->VersionList;
+   map_pointer_t *LastVer = &Pkg->VersionList;
    void const * oldMap = Map.Data();
 
    unsigned short const Hash = List.VersionHash();
@@ -364,7 +362,7 @@ bool pkgCacheGenerator::MergeListVersion(ListParser &List, pkgCache::PkgIterator
       /* We know the list is sorted so we use that fact in the search.
          Insertion of new versions is done with correct sorting */
       int Res = 1;
-      for (; Ver.end() == false; LastVer = &Ver->NextVer, Ver++)
+      for (; Ver.end() == false; LastVer = &Ver->NextVer, ++Ver)
       {
 	 Res = Cache.VS->CmpVersion(Version,Ver.VerStr());
 	 // Version is higher as current version - insert here
@@ -400,13 +398,13 @@ bool pkgCacheGenerator::MergeListVersion(ListParser &List, pkgCache::PkgIterator
    }
 
    // Add a new version
-   map_ptrloc const verindex = NewVersion(Ver, Version, Pkg.Index(), Hash, *LastVer);
+   map_pointer_t const verindex = NewVersion(Ver, Version, Pkg.Index(), Hash, *LastVer);
    if (verindex == 0 && _error->PendingError())
       return _error->Error(_("Error occurred while processing %s (%s%d)"),
 			   Pkg.Name(), "NewVersion", 1);
 
    if (oldMap != Map.Data())
-	 LastVer += (map_ptrloc const * const) Map.Data() - (map_ptrloc const * const) oldMap;
+	 LastVer += (map_pointer_t const * const) Map.Data() - (map_pointer_t const * const) oldMap;
    *LastVer = verindex;
 
    if (unlikely(List.NewVersion(Ver) == false))
@@ -467,7 +465,7 @@ bool pkgCacheGenerator::MergeListVersion(ListParser &List, pkgCache::PkgIterator
 		   D.ParentPkg().Group() == Grp)
 		  continue;
 
-	       map_ptrloc *OldDepLast = NULL;
+	       map_pointer_t *OldDepLast = NULL;
 	       pkgCache::VerIterator ConVersion = D.ParentVer();
 	       Dynamic<pkgCache::VerIterator> DynV(ConVersion);
 	       // duplicate the Conflicts/Breaks/Replaces for :none arch
@@ -509,7 +507,7 @@ bool pkgCacheGenerator::MergeListVersion(ListParser &List, pkgCache::PkgIterator
    }
 
    // We haven't found reusable descriptions, so add the first description(s)
-   map_ptrloc md5idx = Ver->DescriptionList == 0 ? 0 : Ver.DescriptionList()->md5sum;
+   map_stringitem_t md5idx = Ver->DescriptionList == 0 ? 0 : Ver.DescriptionList()->md5sum;
    std::vector<std::string> availDesc = List.AvailableDescriptionLanguages();
    for (std::vector<std::string>::const_iterator CurLang = availDesc.begin(); CurLang != availDesc.end(); ++CurLang)
       if (AddNewDescription(List, Ver, *CurLang, CurMd5, md5idx) == false)
@@ -517,12 +515,12 @@ bool pkgCacheGenerator::MergeListVersion(ListParser &List, pkgCache::PkgIterator
    return true;
 }
 									/*}}}*/
-bool pkgCacheGenerator::AddNewDescription(ListParser &List, pkgCache::VerIterator &Ver, std::string const &lang, MD5SumValue const &CurMd5, map_ptrloc &md5idx) /*{{{*/
+bool pkgCacheGenerator::AddNewDescription(ListParser &List, pkgCache::VerIterator &Ver, std::string const &lang, MD5SumValue const &CurMd5, map_stringitem_t &md5idx) /*{{{*/
 {
    pkgCache::DescIterator Desc;
    Dynamic<pkgCache::DescIterator> DynDesc(Desc);
 
-   map_ptrloc const descindex = NewDescription(Desc, lang, CurMd5, md5idx);
+   map_pointer_t const descindex = NewDescription(Desc, lang, CurMd5, md5idx);
    if (unlikely(descindex == 0 && _error->PendingError()))
       return _error->Error(_("Error occurred while processing %s (%s%d)"),
 	    Ver.ParentPkg().Name(), "NewDescription", 1);
@@ -534,7 +532,7 @@ bool pkgCacheGenerator::AddNewDescription(ListParser &List, pkgCache::VerIterato
    // that to be able to efficiently share these lists
    pkgCache::DescIterator VerDesc = Ver.DescriptionList(); // old value might be invalid after ReMap
    for (;VerDesc.end() == false && VerDesc->NextDesc != 0; ++VerDesc);
-   map_ptrloc * const LastNextDesc = (VerDesc.end() == true) ? &Ver->DescriptionList : &VerDesc->NextDesc;
+   map_pointer_t * const LastNextDesc = (VerDesc.end() == true) ? &Ver->DescriptionList : &VerDesc->NextDesc;
    *LastNextDesc = descindex;
 
    if (NewFileDesc(Desc,List) == false)
@@ -606,19 +604,19 @@ bool pkgCacheGenerator::NewGroup(pkgCache::GrpIterator &Grp, const string &Name)
       return true;
 
    // Get a structure
-   map_ptrloc const Group = AllocateInMap(sizeof(pkgCache::Group));
+   map_pointer_t const Group = AllocateInMap(sizeof(pkgCache::Group));
    if (unlikely(Group == 0))
       return false;
 
    Grp = pkgCache::GrpIterator(Cache, Cache.GrpP + Group);
-   map_ptrloc const idxName = WriteStringInMap(Name);
+   map_stringitem_t const idxName = StoreString(PKGNAME, Name);
    if (unlikely(idxName == 0))
       return false;
    Grp->Name = idxName;
 
    // Insert it into the hash table
    unsigned long const Hash = Cache.Hash(Name);
-   map_ptrloc *insertAt = &Cache.HeaderP->GrpHashTable[Hash];
+   map_pointer_t *insertAt = &Cache.HeaderP->GrpHashTable()[Hash];
    while (*insertAt != 0 && strcasecmp(Name.c_str(), Cache.StrP + (Cache.GrpP + *insertAt)->Name) > 0)
       insertAt = &(Cache.GrpP + *insertAt)->Next;
    Grp->Next = *insertAt;
@@ -643,7 +641,7 @@ bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator &Pkg,const string &Name
 	 return true;
 
    // Get a structure
-   map_ptrloc const Package = AllocateInMap(sizeof(pkgCache::Package));
+   map_pointer_t const Package = AllocateInMap(sizeof(pkgCache::Package));
    if (unlikely(Package == 0))
       return false;
    Pkg = pkgCache::PkgIterator(Cache,Cache.PkgP + Package);
@@ -653,27 +651,34 @@ bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator &Pkg,const string &Name
    {
       Grp->FirstPackage = Package;
       // Insert it into the hash table
-      unsigned long const Hash = Cache.Hash(Name);
-      map_ptrloc *insertAt = &Cache.HeaderP->PkgHashTable[Hash];
-      while (*insertAt != 0 && strcasecmp(Name.c_str(), Cache.StrP + (Cache.PkgP + *insertAt)->Name) > 0)
-	 insertAt = &(Cache.PkgP + *insertAt)->NextPackage;
-      Pkg->NextPackage = *insertAt;
+      map_id_t const Hash = Cache.Hash(Name);
+      map_pointer_t *insertAt = &Cache.HeaderP->PkgHashTable()[Hash];
+      while (*insertAt != 0 && strcasecmp(Name.c_str(), Cache.StrP + (Cache.GrpP + (Cache.PkgP + *insertAt)->Group)->Name) > 0)
+	 insertAt = &(Cache.PkgP + *insertAt)->Next;
+      Pkg->Next = *insertAt;
       *insertAt = Package;
    }
    else // Group the Packages together
    {
       // this package is the new last package
       pkgCache::PkgIterator LastPkg(Cache, Cache.PkgP + Grp->LastPackage);
-      Pkg->NextPackage = LastPkg->NextPackage;
-      LastPkg->NextPackage = Package;
+      Pkg->Next = LastPkg->Next;
+      LastPkg->Next = Package;
    }
    Grp->LastPackage = Package;
 
    // Set the name, arch and the ID
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic push
+	#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
    Pkg->Name = Grp->Name;
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic pop
+#endif
    Pkg->Group = Grp.Index();
    // all is mapped to the native architecture
-   map_ptrloc const idxArch = (Arch == "all") ? Cache.HeaderP->Architecture : WriteUniqString(Arch.c_str());
+   map_stringitem_t const idxArch = (Arch == "all") ? Cache.HeaderP->Architecture : StoreString(MIXED, Arch);
    if (unlikely(idxArch == 0))
       return false;
    Pkg->Arch = idxArch;
@@ -690,14 +695,14 @@ bool pkgCacheGenerator::AddImplicitDepends(pkgCache::GrpIterator &G,
    // copy P.Arch() into a string here as a cache remap
    // in NewDepends() later may alter the pointer location
    string Arch = P.Arch() == NULL ? "" : P.Arch();
-   map_ptrloc *OldDepLast = NULL;
+   map_pointer_t *OldDepLast = NULL;
    /* MultiArch handling introduces a lot of implicit Dependencies:
       - MultiArch: same → Co-Installable if they have the same version
       - All others conflict with all other group members */
    bool const coInstall = ((V->MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same);
    pkgCache::PkgIterator D = G.PackageList();
    Dynamic<pkgCache::PkgIterator> DynD(D);
-   map_ptrloc const VerStrIdx = V->VerStr;
+   map_stringitem_t const VerStrIdx = V->VerStr;
    for (; D.end() != true; D = G.NextPkg(D))
    {
       if (Arch == D.Arch() || D->VersionList == 0)
@@ -730,11 +735,11 @@ bool pkgCacheGenerator::AddImplicitDepends(pkgCache::VerIterator &V,
    /* MultiArch handling introduces a lot of implicit Dependencies:
       - MultiArch: same → Co-Installable if they have the same version
       - All others conflict with all other group members */
-   map_ptrloc *OldDepLast = NULL;
+   map_pointer_t *OldDepLast = NULL;
    bool const coInstall = ((V->MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same);
    if (coInstall == true)
    {
-      map_ptrloc const VerStrIdx = V->VerStr;
+      map_stringitem_t const VerStrIdx = V->VerStr;
       // Replaces: ${self}:other ( << ${binary:Version})
       NewDepends(D, V, VerStrIdx,
 		 pkgCache::Dep::Less, pkgCache::Dep::Replaces,
@@ -763,15 +768,15 @@ bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator &Ver,
       return true;
    
    // Get a structure
-   map_ptrloc const VerFile = AllocateInMap(sizeof(pkgCache::VerFile));
+   map_pointer_t const VerFile = AllocateInMap(sizeof(pkgCache::VerFile));
    if (VerFile == 0)
-      return 0;
+      return false;
    
    pkgCache::VerFileIterator VF(Cache,Cache.VerFileP + VerFile);
    VF->File = CurrentFile - Cache.PkgFileP;
    
    // Link it to the end of the list
-   map_ptrloc *Last = &Ver->FileList;
+   map_pointer_t *Last = &Ver->FileList;
    for (pkgCache::VerFileIterator V = Ver.FileList(); V.end() == false; ++V)
       Last = &V->NextFile;
    VF->NextFile = *Last;
@@ -789,14 +794,14 @@ bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator &Ver,
 // CacheGenerator::NewVersion - Create a new Version 			/*{{{*/
 // ---------------------------------------------------------------------
 /* This puts a version structure in the linked list */
-unsigned long pkgCacheGenerator::NewVersion(pkgCache::VerIterator &Ver,
+map_pointer_t pkgCacheGenerator::NewVersion(pkgCache::VerIterator &Ver,
 					    const string &VerStr,
-					    map_ptrloc const ParentPkg,
-					    unsigned long const Hash,
-					    unsigned long Next)
+					    map_pointer_t const ParentPkg,
+					    unsigned short const Hash,
+					    map_pointer_t const Next)
 {
    // Get a structure
-   map_ptrloc const Version = AllocateInMap(sizeof(pkgCache::Version));
+   map_pointer_t const Version = AllocateInMap(sizeof(pkgCache::Version));
    if (Version == 0)
       return 0;
    
@@ -831,7 +836,7 @@ unsigned long pkgCacheGenerator::NewVersion(pkgCache::VerIterator &Ver,
       }
    }
    // haven't found the version string, so create
-   map_ptrloc const idxVerStr = WriteStringInMap(VerStr);
+   map_stringitem_t const idxVerStr = StoreString(VERSIONNUMBER, VerStr);
    if (unlikely(idxVerStr == 0))
       return 0;
    Ver->VerStr = idxVerStr;
@@ -848,7 +853,7 @@ bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator &Desc,
       return true;
    
    // Get a structure
-   map_ptrloc const DescFile = AllocateInMap(sizeof(pkgCache::DescFile));
+   map_pointer_t const DescFile = AllocateInMap(sizeof(pkgCache::DescFile));
    if (DescFile == 0)
       return false;
 
@@ -856,7 +861,7 @@ bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator &Desc,
    DF->File = CurrentFile - Cache.PkgFileP;
 
    // Link it to the end of the list
-   map_ptrloc *Last = &Desc->FileList;
+   map_pointer_t *Last = &Desc->FileList;
    for (pkgCache::DescFileIterator D = Desc.FileList(); D.end() == false; ++D)
       Last = &D->NextFile;
 
@@ -875,20 +880,20 @@ bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator &Desc,
 // CacheGenerator::NewDescription - Create a new Description		/*{{{*/
 // ---------------------------------------------------------------------
 /* This puts a description structure in the linked list */
-map_ptrloc pkgCacheGenerator::NewDescription(pkgCache::DescIterator &Desc,
+map_pointer_t pkgCacheGenerator::NewDescription(pkgCache::DescIterator &Desc,
 					    const string &Lang,
 					    const MD5SumValue &md5sum,
-					    map_ptrloc idxmd5str)
+					    map_stringitem_t const idxmd5str)
 {
    // Get a structure
-   map_ptrloc const Description = AllocateInMap(sizeof(pkgCache::Description));
+   map_pointer_t const Description = AllocateInMap(sizeof(pkgCache::Description));
    if (Description == 0)
       return 0;
 
    // Fill it in
    Desc = pkgCache::DescIterator(Cache,Cache.DescP + Description);
    Desc->ID = Cache.HeaderP->DescriptionCount++;
-   map_ptrloc const idxlanguage_code = WriteUniqString(Lang);
+   map_stringitem_t const idxlanguage_code = StoreString(MIXED, Lang);
    if (unlikely(idxlanguage_code == 0))
       return 0;
    Desc->language_code = idxlanguage_code;
@@ -897,7 +902,7 @@ map_ptrloc pkgCacheGenerator::NewDescription(pkgCache::DescIterator &Desc,
       Desc->md5sum = idxmd5str;
    else
    {
-      map_ptrloc const idxmd5sum = WriteStringInMap(md5sum.Value());
+      map_stringitem_t const idxmd5sum = WriteStringInMap(md5sum.Value());
       if (unlikely(idxmd5sum == 0))
 	 return 0;
       Desc->md5sum = idxmd5sum;
@@ -915,9 +920,9 @@ bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator &Pkg,
 				   string const &Version,
 				   unsigned int const &Op,
 				   unsigned int const &Type,
-				   map_ptrloc* &OldDepLast)
+				   map_stringitem_t* &OldDepLast)
 {
-   map_ptrloc index = 0;
+   map_stringitem_t index = 0;
    if (Version.empty() == false)
    {
       int const CmpOp = Op & 0x0F;
@@ -928,25 +933,25 @@ bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator &Pkg,
       if (index == 0)
       {
 	 void const * const oldMap = Map.Data();
-	 index = WriteStringInMap(Version);
+	 index = StoreString(VERSIONNUMBER, Version);
 	 if (unlikely(index == 0))
 	    return false;
 	 if (OldDepLast != 0 && oldMap != Map.Data())
-	    OldDepLast += (map_ptrloc const * const) Map.Data() - (map_ptrloc const * const) oldMap;
+	    OldDepLast += (map_pointer_t const * const) Map.Data() - (map_pointer_t const * const) oldMap;
       }
    }
    return NewDepends(Pkg, Ver, index, Op, Type, OldDepLast);
 }
 bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator &Pkg,
 				   pkgCache::VerIterator &Ver,
-				   map_ptrloc const Version,
+				   map_pointer_t const Version,
 				   unsigned int const &Op,
 				   unsigned int const &Type,
-				   map_ptrloc* &OldDepLast)
+				   map_pointer_t* &OldDepLast)
 {
    void const * const oldMap = Map.Data();
    // Get a structure
-   map_ptrloc const Dependency = AllocateInMap(sizeof(pkgCache::Dependency));
+   map_pointer_t const Dependency = AllocateInMap(sizeof(pkgCache::Dependency));
    if (unlikely(Dependency == 0))
       return false;
 
@@ -971,7 +976,7 @@ bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator &Pkg,
       for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; ++D)
 	 OldDepLast = &D->NextDepends;
    } else if (oldMap != Map.Data())
-      OldDepLast += (map_ptrloc const * const) Map.Data() - (map_ptrloc const * const) oldMap;
+      OldDepLast += (map_pointer_t const * const) Map.Data() - (map_pointer_t const * const) oldMap;
 
    Dep->NextDepends = *OldDepLast;
    *OldDepLast = Dep.Index();
@@ -1036,7 +1041,7 @@ bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator &Ver,
       return true;
    
    // Get a structure
-   map_ptrloc const Provides = Owner->AllocateInMap(sizeof(pkgCache::Provides));
+   map_pointer_t const Provides = Owner->AllocateInMap(sizeof(pkgCache::Provides));
    if (unlikely(Provides == 0))
       return false;
    Cache.HeaderP->ProvidesCount++;
@@ -1048,7 +1053,7 @@ bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator &Ver,
    Prv->NextPkgProv = Ver->ProvidesList;
    Ver->ProvidesList = Prv.Index();
    if (Version.empty() == false) {
-      map_ptrloc const idxProvideVersion = WriteString(Version);
+      map_stringitem_t const idxProvideVersion = WriteString(Version);
       Prv->ProvideVersion = idxProvideVersion;
       if (unlikely(idxProvideVersion == 0))
 	 return false;
@@ -1083,14 +1088,14 @@ bool pkgCacheGenerator::SelectFile(const string &File,const string &Site,
 				   unsigned long Flags)
 {
    // Get some space for the structure
-   map_ptrloc const idxFile = AllocateInMap(sizeof(*CurrentFile));
+   map_pointer_t const idxFile = AllocateInMap(sizeof(*CurrentFile));
    if (unlikely(idxFile == 0))
       return false;
    CurrentFile = Cache.PkgFileP + idxFile;
 
    // Fill it in
-   map_ptrloc const idxFileName = WriteStringInMap(File);
-   map_ptrloc const idxSite = WriteUniqString(Site);
+   map_stringitem_t const idxFileName = WriteStringInMap(File);
+   map_stringitem_t const idxSite = StoreString(MIXED, Site);
    if (unlikely(idxFileName == 0 || idxSite == 0))
       return false;
    CurrentFile->FileName = idxFileName;
@@ -1098,7 +1103,7 @@ bool pkgCacheGenerator::SelectFile(const string &File,const string &Site,
    CurrentFile->NextFile = Cache.HeaderP->FileList;
    CurrentFile->Flags = Flags;
    CurrentFile->ID = Cache.HeaderP->PackageFileCount;
-   map_ptrloc const idxIndexType = WriteUniqString(Index.GetType()->Label);
+   map_stringitem_t const idxIndexType = StoreString(MIXED, Index.GetType()->Label);
    if (unlikely(idxIndexType == 0))
       return false;
    CurrentFile->IndexType = idxIndexType;
@@ -1115,57 +1120,27 @@ bool pkgCacheGenerator::SelectFile(const string &File,const string &Site,
 // ---------------------------------------------------------------------
 /* This is used to create handles to strings. Given the same text it
    always returns the same number */
-unsigned long pkgCacheGenerator::WriteUniqString(const char *S,
+map_stringitem_t pkgCacheGenerator::StoreString(enum StringType const type, const char *S,
 						 unsigned int Size)
 {
-   /* We use a very small transient hash table here, this speeds up generation
-      by a fair amount on slower machines */
-   pkgCache::StringItem *&Bucket = UniqHash[(S[0]*5 + S[1]) % _count(UniqHash)];
-   if (Bucket != 0 && 
-       stringcmp(S,S+Size,Cache.StrP + Bucket->String) == 0)
-      return Bucket->String;
-   
-   // Search for an insertion point
-   pkgCache::StringItem *I = Cache.StringItemP + Cache.HeaderP->StringList;
-   int Res = 1;
-   map_ptrloc *Last = &Cache.HeaderP->StringList;
-   for (; I != Cache.StringItemP; Last = &I->NextItem, 
-        I = Cache.StringItemP + I->NextItem)
-   {
-      Res = stringcmp(S,S+Size,Cache.StrP + I->String);
-      if (Res >= 0)
-	 break;
-   }
-   
-   // Match
-   if (Res == 0)
-   {
-      Bucket = I;
-      return I->String;
-   }
-   
-   // Get a structure
-   void const * const oldMap = Map.Data();
-   map_ptrloc const Item = AllocateInMap(sizeof(pkgCache::StringItem));
-   if (Item == 0)
-      return 0;
-
-   map_ptrloc const idxString = WriteStringInMap(S,Size);
-   if (unlikely(idxString == 0))
-      return 0;
-   if (oldMap != Map.Data()) {
-      Last += (map_ptrloc const * const) Map.Data() - (map_ptrloc const * const) oldMap;
-      I += (pkgCache::StringItem const * const) Map.Data() - (pkgCache::StringItem const * const) oldMap;
+   std::string const key(S, Size);
+
+   std::map<std::string,map_stringitem_t> * strings;
+   switch(type) {
+      case MIXED: strings = &strMixed; break;
+      case PKGNAME: strings = &strPkgNames; break;
+      case VERSIONNUMBER: strings = &strVersions; break;
+      case SECTION: strings = &strSections; break;
+      default: _error->Fatal("Unknown enum type used for string storage of '%s'", key.c_str()); return 0;
    }
-   *Last = Item;
 
-   // Fill in the structure
-   pkgCache::StringItem *ItemP = Cache.StringItemP + Item;
-   ItemP->NextItem = I - Cache.StringItemP;
-   ItemP->String = idxString;
+   std::map<std::string,map_stringitem_t>::const_iterator const item = strings->find(key);
+   if (item != strings->end())
+      return item->second;
 
-   Bucket = ItemP;
-   return ItemP->String;
+   map_stringitem_t const idxString = WriteStringInMap(S,Size);
+   strings->insert(std::make_pair(key, idxString));
+   return idxString;
 }
 									/*}}}*/
 // CheckValidity - Check that a cache is up-to-date			/*{{{*/
@@ -1275,9 +1250,9 @@ static bool CheckValidity(const string &CacheFile,
 // ---------------------------------------------------------------------
 /* Size is kind of an abstract notion that is only used for the progress
    meter */
-static unsigned long ComputeSize(FileIterator Start,FileIterator End)
+static map_filesize_t ComputeSize(FileIterator Start,FileIterator End)
 {
-   unsigned long TotalSize = 0;
+   map_filesize_t TotalSize = 0;
    for (; Start < End; ++Start)
    {
       if ((*Start)->HasPackages() == false)
@@ -1292,7 +1267,7 @@ static unsigned long ComputeSize(FileIterator Start,FileIterator End)
 /* */
 static bool BuildCache(pkgCacheGenerator &Gen,
 		       OpProgress *Progress,
-		       unsigned long &CurrentSize,unsigned long TotalSize,
+		       map_filesize_t &CurrentSize,map_filesize_t TotalSize,
 		       FileIterator Start, FileIterator End)
 {
    FileIterator I;
@@ -1311,7 +1286,7 @@ static bool BuildCache(pkgCacheGenerator &Gen,
 	 continue;
       }
       
-      unsigned long Size = (*I)->Size();
+      map_filesize_t Size = (*I)->Size();
       if (Progress != NULL)
 	 Progress->OverallProgress(CurrentSize,TotalSize,Size,_("Reading package lists"));
       CurrentSize += Size;
@@ -1328,7 +1303,7 @@ static bool BuildCache(pkgCacheGenerator &Gen,
       CurrentSize = 0;
       for (I = Start; I != End; ++I)
       {
-	 unsigned long Size = (*I)->Size();
+	 map_filesize_t Size = (*I)->Size();
 	 if (Progress != NULL)
 	    Progress->OverallProgress(CurrentSize,TotalSize,Size,_("Collecting File Provides"));
 	 CurrentSize += Size;
@@ -1342,9 +1317,9 @@ static bool BuildCache(pkgCacheGenerator &Gen,
 									/*}}}*/
 // CacheGenerator::CreateDynamicMMap - load an mmap with configuration options	/*{{{*/
 DynamicMMap* pkgCacheGenerator::CreateDynamicMMap(FileFd *CacheF, unsigned long Flags) {
-   unsigned long const MapStart = _config->FindI("APT::Cache-Start", 24*1024*1024);
-   unsigned long const MapGrow = _config->FindI("APT::Cache-Grow", 1*1024*1024);
-   unsigned long const MapLimit = _config->FindI("APT::Cache-Limit", 0);
+   map_filesize_t const MapStart = _config->FindI("APT::Cache-Start", 24*1024*1024);
+   map_filesize_t const MapGrow = _config->FindI("APT::Cache-Grow", 1*1024*1024);
+   map_filesize_t const MapLimit = _config->FindI("APT::Cache-Limit", 0);
    Flags |= MMap::Moveable;
    if (_config->FindB("APT::Cache-Fallback", false) == true)
       Flags |= MMap::Fallback;
@@ -1382,7 +1357,7 @@ bool pkgCacheGenerator::MakeStatusCache(pkgSourceList &List,OpProgress *Progress
          Files.push_back (*j);
    }
    
-   unsigned long const EndOfSource = Files.size();
+   map_filesize_t const EndOfSource = Files.size();
    if (_system->AddStatusFiles(Files) == false)
       return false;
 
@@ -1472,8 +1447,8 @@ bool pkgCacheGenerator::MakeStatusCache(pkgSourceList &List,OpProgress *Progress
    }
    
    // Lets try the source cache.
-   unsigned long CurrentSize = 0;
-   unsigned long TotalSize = 0;
+   map_filesize_t CurrentSize = 0;
+   map_filesize_t TotalSize = 0;
    if (CheckValidity(SrcCacheFile, List, Files.begin(),
 		     Files.begin()+EndOfSource) == true)
    {
@@ -1481,7 +1456,7 @@ bool pkgCacheGenerator::MakeStatusCache(pkgSourceList &List,OpProgress *Progress
 	 std::clog << "srcpkgcache.bin is valid - populate MMap with it." << std::endl;
       // Preload the map with the source cache
       FileFd SCacheF(SrcCacheFile,FileFd::ReadOnly);
-      unsigned long const alloc = Map->RawAllocate(SCacheF.Size());
+      map_pointer_t const alloc = Map->RawAllocate(SCacheF.Size());
       if ((alloc == 0 && _error->PendingError())
 		|| SCacheF.Read((unsigned char *)Map->Data() + alloc,
 				SCacheF.Size()) == false)
@@ -1568,13 +1543,13 @@ APT_DEPRECATED bool pkgMakeOnlyStatusCache(OpProgress &Progress,DynamicMMap **Ou
 bool pkgCacheGenerator::MakeOnlyStatusCache(OpProgress *Progress,DynamicMMap **OutMap)
 {
    std::vector<pkgIndexFile *> Files;
-   unsigned long EndOfSource = Files.size();
+   map_filesize_t EndOfSource = Files.size();
    if (_system->AddStatusFiles(Files) == false)
       return false;
 
    SPtr<DynamicMMap> Map = CreateDynamicMMap(NULL);
-   unsigned long CurrentSize = 0;
-   unsigned long TotalSize = 0;
+   map_filesize_t CurrentSize = 0;
+   map_filesize_t TotalSize = 0;
    
    TotalSize = ComputeSize(Files.begin()+EndOfSource,Files.end());
    

+ 30 - 24
apt-pkg/pkgcachegen.h

@@ -27,6 +27,7 @@
 
 #include <vector>
 #include <string>
+#include <map>
 
 class FileFd;
 class pkgSourceList;
@@ -36,12 +37,15 @@ class pkgIndexFile;
 class pkgCacheGenerator							/*{{{*/
 {
    private:
+   APT_HIDDEN map_stringitem_t WriteStringInMap(std::string const &String) { return WriteStringInMap(String.c_str()); };
+   APT_HIDDEN map_stringitem_t WriteStringInMap(const char *String);
+   APT_HIDDEN map_stringitem_t WriteStringInMap(const char *String, const unsigned long &Len);
+   APT_HIDDEN map_pointer_t AllocateInMap(const unsigned long &size);
 
-   pkgCache::StringItem *UniqHash[26];
-   APT_HIDDEN map_ptrloc WriteStringInMap(std::string const &String) { return WriteStringInMap(String.c_str()); };
-   APT_HIDDEN map_ptrloc WriteStringInMap(const char *String);
-   APT_HIDDEN map_ptrloc WriteStringInMap(const char *String, const unsigned long &Len);
-   APT_HIDDEN map_ptrloc AllocateInMap(const unsigned long &size);
+   std::map<std::string,map_stringitem_t> strMixed;
+   std::map<std::string,map_stringitem_t> strSections;
+   std::map<std::string,map_stringitem_t> strPkgNames;
+   std::map<std::string,map_stringitem_t> strVersions;
 
    public:
    
@@ -78,21 +82,22 @@ class pkgCacheGenerator							/*{{{*/
    bool NewFileDesc(pkgCache::DescIterator &Desc,ListParser &List);
    bool NewDepends(pkgCache::PkgIterator &Pkg, pkgCache::VerIterator &Ver,
 		   std::string const &Version, unsigned int const &Op,
-		   unsigned int const &Type, map_ptrloc* &OldDepLast);
+		   unsigned int const &Type, map_pointer_t* &OldDepLast);
    bool NewDepends(pkgCache::PkgIterator &Pkg, pkgCache::VerIterator &Ver,
-		   map_ptrloc const Version, unsigned int const &Op,
-		   unsigned int const &Type, map_ptrloc* &OldDepLast);
-   unsigned long NewVersion(pkgCache::VerIterator &Ver,const std::string &VerStr,unsigned long Next) APT_DEPRECATED
+		   map_pointer_t const Version, unsigned int const &Op,
+		   unsigned int const &Type, map_pointer_t* &OldDepLast);
+   map_pointer_t NewVersion(pkgCache::VerIterator &Ver,const std::string &VerStr,map_pointer_t const Next) APT_DEPRECATED
    { return NewVersion(Ver, VerStr, 0, 0, Next); }
-   unsigned long NewVersion(pkgCache::VerIterator &Ver,const std::string &VerStr,
-			    map_ptrloc const ParentPkg, unsigned long const Hash,
-			    unsigned long Next);
-   map_ptrloc NewDescription(pkgCache::DescIterator &Desc,const std::string &Lang,const MD5SumValue &md5sum,map_ptrloc Next);
+   map_pointer_t NewVersion(pkgCache::VerIterator &Ver,const std::string &VerStr,
+			    map_pointer_t const ParentPkg, unsigned short const Hash,
+			    map_pointer_t const Next);
+   map_pointer_t NewDescription(pkgCache::DescIterator &Desc,const std::string &Lang,const MD5SumValue &md5sum,map_stringitem_t const idxmd5str);
 
    public:
 
-   unsigned long WriteUniqString(const char *S,unsigned int Size);
-   inline unsigned long WriteUniqString(const std::string &S) {return WriteUniqString(S.c_str(),S.length());};
+   enum StringType { MIXED, PKGNAME, VERSIONNUMBER, SECTION };
+   map_stringitem_t StoreString(StringType const type, const char * S, unsigned int const Size);
+   inline map_stringitem_t StoreString(enum StringType const type, const std::string &S) {return StoreString(type, S.c_str(),S.length());};
 
    void DropProgress() {Progress = 0;};
    bool SelectFile(const std::string &File,const std::string &Site,pkgIndexFile const &Index,
@@ -127,7 +132,7 @@ class pkgCacheGenerator							/*{{{*/
    APT_HIDDEN bool AddImplicitDepends(pkgCache::VerIterator &V, pkgCache::PkgIterator &D);
 
    APT_HIDDEN bool AddNewDescription(ListParser &List, pkgCache::VerIterator &Ver,
-	 std::string const &lang, MD5SumValue const &CurMd5, map_ptrloc &md5idx);
+	 std::string const &lang, MD5SumValue const &CurMd5, map_stringitem_t &md5idx);
 };
 									/*}}}*/
 // This is the abstract package list parser class.			/*{{{*/
@@ -138,17 +143,18 @@ class pkgCacheGenerator::ListParser
    
    // Some cache items
    pkgCache::VerIterator OldDepVer;
-   map_ptrloc *OldDepLast;
+   map_pointer_t *OldDepLast;
 
    // Flag file dependencies
    bool FoundFileDeps;
       
    protected:
 
-   inline unsigned long WriteUniqString(std::string S) {return Owner->WriteUniqString(S);};
-   inline unsigned long WriteUniqString(const char *S,unsigned int Size) {return Owner->WriteUniqString(S,Size);};
-   inline unsigned long WriteString(const std::string &S) {return Owner->WriteStringInMap(S);};
-   inline unsigned long WriteString(const char *S,unsigned int Size) {return Owner->WriteStringInMap(S,Size);};
+   inline map_stringitem_t StoreString(pkgCacheGenerator::StringType const type, std::string const &S) {return Owner->StoreString(type, S);};
+   inline map_stringitem_t StoreString(pkgCacheGenerator::StringType const type, const char *S,unsigned int Size) {return Owner->StoreString(type, S, Size);};
+
+   inline map_stringitem_t WriteString(const std::string &S) {return Owner->WriteStringInMap(S);};
+   inline map_stringitem_t WriteString(const char *S,unsigned int Size) {return Owner->WriteStringInMap(S,Size);};
    bool NewDepends(pkgCache::VerIterator &Ver,const std::string &Package, const std::string &Arch,
 		   const std::string &Version,unsigned int Op,
 		   unsigned int Type);
@@ -178,8 +184,8 @@ class pkgCacheGenerator::ListParser
       APT_PURE bool SameVersion(unsigned short const Hash, pkgCache::VerIterator const &Ver);
    virtual bool UsePackage(pkgCache::PkgIterator &Pkg,
 			   pkgCache::VerIterator &Ver) = 0;
-   virtual unsigned long Offset() = 0;
-   virtual unsigned long Size() = 0;
+   virtual map_filesize_t Offset() = 0;
+   virtual map_filesize_t Size() = 0;
    
    virtual bool Step() = 0;
    
@@ -187,7 +193,7 @@ class pkgCacheGenerator::ListParser
    virtual bool CollectFileProvides(pkgCache &/*Cache*/,
 				    pkgCache::VerIterator &/*Ver*/) {return true;};
 
-   ListParser() : FoundFileDeps(false) {};
+   ListParser() : Owner(NULL), OldDepLast(NULL), FoundFileDeps(false) {};
    virtual ~ListParser() {};
 };
 									/*}}}*/

+ 4 - 4
apt-pkg/sourcelist.cc

@@ -119,7 +119,7 @@ bool pkgSourceList::Type::ParseStanza(vector<metaIndex *> &List,
    std::vector<std::string> list_section = StringSplit(Section, " ");
    
    for (std::vector<std::string>::const_iterator U = list_uris.begin();
-        U != list_uris.end(); U++)
+        U != list_uris.end(); ++U)
    {
       std::string URI = (*U);
       if (!FixupURI(URI))
@@ -129,10 +129,10 @@ bool pkgSourceList::Type::ParseStanza(vector<metaIndex *> &List,
       }
 
       for (std::vector<std::string>::const_iterator I = list_dist.begin();
-           I != list_dist.end(); I++)
+           I != list_dist.end(); ++I)
       {
          for (std::vector<std::string>::const_iterator J = list_section.begin();
-              J != list_section.end(); J++)
+              J != list_section.end(); ++J)
          {
             if (CreateItem(List, URI, (*I), (*J), Options) == false)
             {
@@ -408,7 +408,7 @@ int pkgSourceList::ParseFileDeb822(string File)
       string const types = Tags.FindS("Types");
       std::vector<std::string> list_types = StringSplit(types, " ");
       for (std::vector<std::string>::const_iterator I = list_types.begin();
-        I != list_types.end(); I++)
+        I != list_types.end(); ++I)
       {
          Type *Parse = Type::GetType((*I).c_str());
          if (Parse == 0)

+ 0 - 4
apt-pkg/sourcelist.h

@@ -96,13 +96,9 @@ class pkgSourceList : public pkgSource
    
    public:
 
-   std::vector<metaIndex *> SrcList;
-
    int ParseFileDeb822(std::string File);
    bool ParseFileOldStyle(std::string File);
 
-   public:
-
    bool ReadMainList();
    bool Read(std::string File);
 

+ 24 - 13
apt-pkg/srcrecords.cc

@@ -81,6 +81,27 @@ bool pkgSrcRecords::Restart()
    return true;
 }
 									/*}}}*/
+// SrcRecords::Step - Step to the next Source Record			/*{{{*/
+// ---------------------------------------------------------------------
+/* Step to the next source package record */
+const pkgSrcRecords::Parser* pkgSrcRecords::Step()
+{
+   if (Current == Files.end())
+      return 0;
+
+   // Step to the next record, possibly switching files
+   while ((*Current)->Step() == false)
+   {
+      if (_error->PendingError() == true)
+         return 0;
+      ++Current;
+      if (Current == Files.end())
+         return 0;
+   }
+
+   return *Current;
+}
+									/*}}}*/
 // SrcRecords::Find - Find the first source package with the given name	/*{{{*/
 // ---------------------------------------------------------------------
 /* This searches on both source package names and output binary names and
@@ -88,21 +109,11 @@ bool pkgSrcRecords::Restart()
    function to be called multiple times to get successive entries */
 pkgSrcRecords::Parser *pkgSrcRecords::Find(const char *Package,bool const &SrcOnly)
 {
-   if (Current == Files.end())
-      return 0;
-   
    while (true)
    {
-      // Step to the next record, possibly switching files
-      while ((*Current)->Step() == false)
-      {
-	 if (_error->PendingError() == true)
-	    return 0;
-	 ++Current;
-	 if (Current == Files.end())
-	    return 0;
-      }
-      
+      if(Step() == 0)
+         return 0;
+
       // IO error somehow
       if (_error->PendingError() == true)
 	 return 0;

+ 7 - 2
apt-pkg/srcrecords.h

@@ -105,8 +105,13 @@ class pkgSrcRecords
    // Reset the search
    bool Restart();
 
-   // Locate a package by name
-   Parser *Find(const char *Package,bool const &SrcOnly = false);
+   // Step to the next SourcePackage and return pointer to the 
+   // next SourceRecord. The pointer is owned by libapt.
+   const Parser* Step();
+
+   // Locate a package by name and return pointer to the Parser.
+   // The pointer is owned by libapt.
+   Parser* Find(const char *Package,bool const &SrcOnly = false);
    
    pkgSrcRecords(pkgSourceList &List);
    virtual ~pkgSrcRecords();

+ 12 - 1
apt-pkg/tagfile.cc

@@ -518,6 +518,17 @@ unsigned long long pkgTagSection::FindULL(const char *Tag, unsigned long long co
    return Result;
 }
 									/*}}}*/
+// TagSection::FindB - Find boolean value                		/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool pkgTagSection::FindB(const char *Tag, bool const &Default) const
+{
+   const char *Start, *Stop;
+   if (Find(Tag, Start, Stop) == false)
+      return Default;
+   return StringToBool(string(Start, Stop));
+}
+									/*}}}*/
 // TagSection::FindFlag - Locate a yes/no type flag			/*{{{*/
 // ---------------------------------------------------------------------
 /* The bits marked in Flag are masked on/off in Flags */
@@ -590,7 +601,7 @@ static const char *iTFRewritePackageOrder[] = {
                           "Conffiles",
                           "Filename",
                           "Size",
-                          "MD5Sum",
+                          "MD5sum",
                           "SHA1",
                           "SHA256",
                           "SHA512",

+ 4 - 3
apt-pkg/tagfile.h

@@ -43,7 +43,7 @@ class pkgTagSection
       unsigned int StartValue;
       unsigned int NextInBucket;
 
-      TagData(unsigned int const StartTag) : StartTag(StartTag), NextInBucket(0) {}
+      TagData(unsigned int const StartTag) : StartTag(StartTag), EndTag(0), StartValue(0), NextInBucket(0) {}
    };
    std::vector<TagData> Tags;
    unsigned int LookupTable[0x100];
@@ -62,7 +62,8 @@ class pkgTagSection
    bool Find(const char *Tag,const char *&Start, const char *&End) const;
    bool Find(const char *Tag,unsigned int &Pos) const;
    std::string FindS(const char *Tag) const;
-   signed int FindI(const char *Tag,signed long Default = 0) const ;
+   signed int FindI(const char *Tag,signed long Default = 0) const;
+   bool FindB(const char *Tag, bool const &Default = false) const;
    unsigned long long FindULL(const char *Tag, unsigned long long const &Default = 0) const;
    bool FindFlag(const char *Tag,unsigned long &Flags,
 		 unsigned long Flag) const;
@@ -93,7 +94,7 @@ class pkgTagSection
    /** \brief amount of Tags in the current section
     *
     * Note: if a Tag is mentioned repeatly it will be counted multiple
-    * times, but only the last occurance is available via Find methods.
+    * times, but only the last occurrence is available via Find methods.
     */
    unsigned int Count() const;
    bool Exists(const char* const Tag) const;

+ 2 - 1
apt-pkg/update.h

@@ -11,7 +11,8 @@
 #define PKGLIB_UPDATE_H
 
 class pkgAcquireStatus;
-
+class pkgSourceList;
+class pkgAcquire;
 
 bool ListUpdate(pkgAcquireStatus &progress, pkgSourceList &List, int PulseInterval=0);
 bool AcquireUpdate(pkgAcquire &Fetcher, int const PulseInterval = 0,

+ 79 - 32
apt-pkg/upgrade.cc

@@ -24,13 +24,14 @@
    
    The problem resolver is used to resolve the problems.
  */
-bool pkgDistUpgrade(pkgDepCache &Cache)
+bool pkgDistUpgrade(pkgDepCache &Cache, OpProgress * const Progress)
 {
    std::string const solver = _config->Find("APT::Solver", "internal");
-   if (solver != "internal") {
-      OpTextProgress Prog(*_config);
-      return EDSP::ResolveExternal(solver.c_str(), Cache, false, true, false, &Prog);
-   }
+   if (solver != "internal")
+      return EDSP::ResolveExternal(solver.c_str(), Cache, false, true, false, Progress);
+
+   if (Progress != NULL)
+      Progress->OverallProgress(0, 100, 1, _("Calculating upgrade"));
 
    pkgDepCache::ActionGroup group(Cache);
 
@@ -41,12 +42,18 @@ bool pkgDistUpgrade(pkgDepCache &Cache)
       if (I->CurrentVer != 0)
 	 Cache.MarkInstall(I, false, 0, false);
 
+   if (Progress != NULL)
+      Progress->Progress(10);
+
    /* Auto upgrade all installed packages, this provides the basis 
       for the installation */
    for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
       if (I->CurrentVer != 0)
 	 Cache.MarkInstall(I, true, 0, false);
 
+   if (Progress != NULL)
+      Progress->Progress(50);
+
    /* Now, install each essential package which is not installed
       (and not provided by another package in the same name group) */
    std::string essential = _config->Find("pkgCacheGen::Essential", "all");
@@ -77,15 +84,24 @@ bool pkgDistUpgrade(pkgDepCache &Cache)
       for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
 	 if ((I->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
 	    Cache.MarkInstall(I, true, 0, false);
-   
+
+   if (Progress != NULL)
+      Progress->Progress(55);
+
    /* We do it again over all previously installed packages to force 
       conflict resolution on them all. */
    for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
       if (I->CurrentVer != 0)
 	 Cache.MarkInstall(I, false, 0, false);
 
+   if (Progress != NULL)
+      Progress->Progress(65);
+
    pkgProblemResolver Fix(&Cache);
 
+   if (Progress != NULL)
+      Progress->Progress(95);
+
    // Hold back held packages.
    if (_config->FindB("APT::Ignore-Hold",false) == false)
    {
@@ -98,18 +114,22 @@ bool pkgDistUpgrade(pkgDepCache &Cache)
 	 }
       }
    }
-   
-   return Fix.Resolve();
+
+   bool const success = Fix.Resolve(false, Progress);
+   if (Progress != NULL)
+      Progress->Done();
+   return success;
 }
 									/*}}}*/
 // AllUpgradeNoNewPackages - Upgrade but no removals or new pkgs        /*{{{*/
-static bool pkgAllUpgradeNoNewPackages(pkgDepCache &Cache)
+static bool pkgAllUpgradeNoNewPackages(pkgDepCache &Cache, OpProgress * const Progress)
 {
    std::string const solver = _config->Find("APT::Solver", "internal");
-   if (solver != "internal") {
-      OpTextProgress Prog(*_config);
-      return EDSP::ResolveExternal(solver.c_str(), Cache, true, false, false, &Prog);
-   }
+   if (solver != "internal")
+      return EDSP::ResolveExternal(solver.c_str(), Cache, true, false, false, Progress);
+
+   if (Progress != NULL)
+      Progress->OverallProgress(0, 100, 1, _("Calculating upgrade"));
 
    pkgDepCache::ActionGroup group(Cache);
 
@@ -131,8 +151,15 @@ static bool pkgAllUpgradeNoNewPackages(pkgDepCache &Cache)
       if (I->CurrentVer != 0 && Cache[I].InstallVer != 0)
 	 Cache.MarkInstall(I, false, 0, false);
    }
-      
-   return Fix.ResolveByKeep();
+
+   if (Progress != NULL)
+      Progress->Progress(50);
+
+   // resolve remaining issues via keep
+   bool const success = Fix.ResolveByKeep(Progress);
+   if (Progress != NULL)
+      Progress->Done();
+   return success;
 }
 									/*}}}*/
 // AllUpgradeWithNewInstalls - Upgrade + install new packages as needed /*{{{*/
@@ -141,8 +168,15 @@ static bool pkgAllUpgradeNoNewPackages(pkgDepCache &Cache)
  * Upgrade as much as possible without deleting anything (useful for
  * stable systems)
  */
-static bool pkgAllUpgradeWithNewPackages(pkgDepCache &Cache)
+static bool pkgAllUpgradeWithNewPackages(pkgDepCache &Cache, OpProgress * const Progress)
 {
+   std::string const solver = _config->Find("APT::Solver", "internal");
+   if (solver != "internal")
+      return EDSP::ResolveExternal(solver.c_str(), Cache, true, false, false, Progress);
+
+   if (Progress != NULL)
+      Progress->OverallProgress(0, 100, 1, _("Calculating upgrade"));
+
    pkgDepCache::ActionGroup group(Cache);
 
    pkgProblemResolver Fix(&Cache);
@@ -164,18 +198,30 @@ static bool pkgAllUpgradeWithNewPackages(pkgDepCache &Cache)
       }
    }
 
+   if (Progress != NULL)
+      Progress->Progress(10);
+
    // then let auto-install loose
    for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
       if (Cache[I].Install())
 	 Cache.MarkInstall(I, true, 0, false);
 
+   if (Progress != NULL)
+      Progress->Progress(50);
+
    // ... but it may remove stuff, we we need to clean up afterwards again
    for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
       if (Cache[I].Delete() == true)
 	 Cache.MarkKeep(I, false, false);
 
+   if (Progress != NULL)
+      Progress->Progress(60);
+
    // resolve remaining issues via keep
-   return Fix.ResolveByKeep();
+   bool const success = Fix.ResolveByKeep(Progress);
+   if (Progress != NULL)
+      Progress->Done();
+   return success;
 }
 									/*}}}*/
 // AllUpgrade - Upgrade as many packages as possible			/*{{{*/
@@ -183,9 +229,9 @@ static bool pkgAllUpgradeWithNewPackages(pkgDepCache &Cache)
 /* Right now the system must be consistent before this can be called.
    It also will not change packages marked for install, it only tries
    to install packages not marked for install */
-bool pkgAllUpgrade(pkgDepCache &Cache)
+bool pkgAllUpgrade(pkgDepCache &Cache, OpProgress * const Progress)
 {
-   return pkgAllUpgradeNoNewPackages(Cache);
+   return pkgAllUpgradeNoNewPackages(Cache, Progress);
 }
 									/*}}}*/
 // MinimizeUpgrade - Minimizes the set of packages to be upgraded	/*{{{*/
@@ -233,24 +279,25 @@ bool pkgMinimizeUpgrade(pkgDepCache &Cache)
    return true;
 }
 									/*}}}*/
-// APT::Upgrade::Upgrade - Upgrade using a specific strategy     	/*{{{*/
-bool APT::Upgrade::Upgrade(pkgDepCache &Cache, int mode)
+// APT::Upgrade::Upgrade - Upgrade using a specific strategy		/*{{{*/
+bool APT::Upgrade::Upgrade(pkgDepCache &Cache, int mode, OpProgress * const Progress)
 {
-   if (mode == 0) 
-   {
-      return pkgDistUpgrade(Cache);
-   }
+#if __GNUC__ >= 4
+	// the deprecated methods will become our privates, so that is fine
+	#pragma GCC diagnostic push
+	#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+   if (mode == ALLOW_EVERYTHING)
+      return pkgDistUpgrade(Cache, Progress);
    else if ((mode & ~FORBID_REMOVE_PACKAGES) == 0)
-   {
-      return pkgAllUpgradeWithNewPackages(Cache);
-   } 
+      return pkgAllUpgradeWithNewPackages(Cache, Progress);
    else if ((mode & ~(FORBID_REMOVE_PACKAGES|FORBID_INSTALL_NEW_PACKAGES)) == 0)
-   {
-      return pkgAllUpgradeNoNewPackages(Cache);
-   }
+      return pkgAllUpgradeNoNewPackages(Cache, Progress);
    else
       _error->Error("pkgAllUpgrade called with unsupported mode %i", mode);
-
+#if __GNUC__ >= 4
+	#pragma GCC diagnostic pop
+#endif
    return false;
 }
 									/*}}}*/

+ 9 - 5
apt-pkg/upgrade.h

@@ -10,23 +10,27 @@
 #ifndef PKGLIB_UPGRADE_H
 #define PKGLIB_UPGRADE_H
 
+#include <stddef.h>
+#include <apt-pkg/macros.h>
+
 class pkgDepCache;
+class OpProgress;
 
 namespace APT {
    namespace Upgrade {
       // FIXME: make this "enum class UpgradeMode {" once we enable c++11
       enum UpgradeMode {
+	 ALLOW_EVERYTHING = 0,
          FORBID_REMOVE_PACKAGES = 1,
          FORBID_INSTALL_NEW_PACKAGES = 2
       };
-      bool Upgrade(pkgDepCache &Cache, int UpgradeMode);
+      bool Upgrade(pkgDepCache &Cache, int UpgradeMode, OpProgress * const Progress = NULL);
    }
 }
 
 // please use APT::Upgrade::Upgrade() instead
-bool pkgDistUpgrade(pkgDepCache &Cache);
-bool pkgAllUpgrade(pkgDepCache &Cache);
-bool pkgMinimizeUpgrade(pkgDepCache &Cache);
-
+APT_DEPRECATED bool pkgDistUpgrade(pkgDepCache &Cache, OpProgress * const Progress = NULL);
+APT_DEPRECATED bool pkgAllUpgrade(pkgDepCache &Cache, OpProgress * const Progress = NULL);
 
+bool pkgMinimizeUpgrade(pkgDepCache &Cache);
 #endif

+ 2 - 2
apt-private/acqprogress.cc

@@ -202,9 +202,9 @@ bool AcqTextStatus::Pulse(pkgAcquire *Owner)
       S += strlen(S);
 
       // Show the short mode string
-      if (I->CurrentItem->Owner->Mode != 0)
+      if (I->CurrentItem->Owner->ActiveSubprocess.empty() == false)
       {
-	 snprintf(S,End-S," %s",I->CurrentItem->Owner->Mode);
+	 snprintf(S,End-S, " %s", I->CurrentItem->Owner->ActiveSubprocess.c_str());
 	 S += strlen(S);
       }
 

+ 3 - 1
apt-private/private-cachefile.cc

@@ -32,8 +32,10 @@ int CacheFile::NameComp(const void *a,const void *b)
    
    const pkgCache::Package &A = **(pkgCache::Package **)a;
    const pkgCache::Package &B = **(pkgCache::Package **)b;
+   const pkgCache::Group * const GA = SortCache->GrpP + A.Group;
+   const pkgCache::Group * const GB = SortCache->GrpP + B.Group;
 
-   return strcmp(SortCache->StrP + A.Name,SortCache->StrP + B.Name);
+   return strcmp(SortCache->StrP + GA->Name,SortCache->StrP + GB->Name);
 }
 									/*}}}*/
 // CacheFile::Sort - Sort by name					/*{{{*/

+ 46 - 43
apt-private/private-cacheset.cc

@@ -14,74 +14,77 @@
 
 #include <apti18n.h>
 
-bool GetLocalitySortedVersionSet(pkgCacheFile &CacheFile, 
-                                 LocalitySortedVersionSet &output_set,
-                                 OpProgress &progress)
+bool GetLocalitySortedVersionSet(pkgCacheFile &CacheFile,
+                                 APT::VersionContainerInterface * const vci,
+                                 OpProgress * const progress)
 {
     Matcher null_matcher = Matcher();
-    return GetLocalitySortedVersionSet(CacheFile, output_set, 
+    return GetLocalitySortedVersionSet(CacheFile, vci,
                                        null_matcher, progress);
 }
 
-bool GetLocalitySortedVersionSet(pkgCacheFile &CacheFile, 
-                                 LocalitySortedVersionSet &output_set,
+bool GetLocalitySortedVersionSet(pkgCacheFile &CacheFile,
+                                 APT::VersionContainerInterface * const vci,
                                  Matcher &matcher,
-                                 OpProgress &progress)
+                                 OpProgress * const progress)
 {
    pkgCache *Cache = CacheFile.GetPkgCache();
    pkgDepCache *DepCache = CacheFile.GetDepCache();
+   APT::CacheSetHelper helper(false);
 
    int Done=0;
-   progress.SubProgress(Cache->Head().PackageCount, _("Sorting"));
+   if (progress != NULL)
+      progress->SubProgress(Cache->Head().PackageCount, _("Sorting"));
+
+   bool const insertCurrentVer = _config->FindB("APT::Cmd::Installed", false);
+   bool const insertUpgradable = _config->FindB("APT::Cmd::Upgradable", false);
+   bool const insertManualInstalled = _config->FindB("APT::Cmd::Manual-Installed", false);
+
    for (pkgCache::PkgIterator P = Cache->PkgBegin(); P.end() == false; ++P)
    {
-      if (Done%500 == 0)
-         progress.Progress(Done);
-      Done++;
+      if (progress != NULL)
+      {
+	 if (Done % 500 == 0)
+	    progress->Progress(Done);
+	 ++Done;
+      }
+
+      // exclude virtual pkgs
+      if (P->VersionList == 0)
+	 continue;
 
       if ((matcher)(P) == false)
-         continue;
+	 continue;
 
-      // exclude virtual pkgs
-      if (P.VersionList() == 0)
-         continue;
       pkgDepCache::StateCache &state = (*DepCache)[P];
-      if (_config->FindB("APT::Cmd::Installed") == true)
+      if (insertCurrentVer == true)
       {
-         if (P.CurrentVer() != NULL)
-         {
-            output_set.insert(P.CurrentVer());
-         }
+	 if (P->CurrentVer != 0)
+	    vci->FromPackage(vci, CacheFile, P, APT::CacheSetHelper::INSTALLED, helper);
       }
-      else if (_config->FindB("APT::Cmd::Upgradable") == true)
+      else if (insertUpgradable == true)
       {
-         if(P.CurrentVer() && state.Upgradable())
-         {
-             pkgPolicy *policy = CacheFile.GetPolicy();
-             output_set.insert(policy->GetCandidateVer(P));
-         }
+	 if(P.CurrentVer() && state.Upgradable())
+	    vci->FromPackage(vci, CacheFile, P, APT::CacheSetHelper::CANDIDATE, helper);
       }
-      else if (_config->FindB("APT::Cmd::Manual-Installed") == true)
+      else if (insertManualInstalled == true)
       {
-         if (P.CurrentVer() && 
-             ((*DepCache)[P].Flags & pkgCache::Flag::Auto) == false)
-         {
-             pkgPolicy *policy = CacheFile.GetPolicy();
-             output_set.insert(policy->GetCandidateVer(P));
-         }
+	 if (P.CurrentVer() &&
+	       ((*DepCache)[P].Flags & pkgCache::Flag::Auto) == false)
+	    vci->FromPackage(vci, CacheFile, P, APT::CacheSetHelper::CANDIDATE, helper);
       }
-      else 
+      else
       {
-         pkgPolicy *policy = CacheFile.GetPolicy();
-         if (policy->GetCandidateVer(P).IsGood())
-            output_set.insert(policy->GetCandidateVer(P));
-         else 
-            // no candidate, this may happen for packages in 
-            // dpkg "deinstall ok config-file" state - we pick the first ver
-            // (which should be the only one)
-            output_set.insert(P.VersionList());
+         if (vci->FromPackage(vci, CacheFile, P, APT::CacheSetHelper::CANDIDATE, helper) == false)
+	 {
+	    // no candidate, this may happen for packages in
+	    // dpkg "deinstall ok config-file" state - we pick the first ver
+	    // (which should be the only one)
+	    vci->insert(P.VersionList());
+	 }
       }
    }
-   progress.Done();
+   if (progress != NULL)
+      progress->Done();
    return true;
 }

+ 17 - 20
apt-private/private-cacheset.h

@@ -62,13 +62,13 @@ public:
 };
 
 // FIXME: add default argument for OpProgress (or overloaded function)
-bool GetLocalitySortedVersionSet(pkgCacheFile &CacheFile, 
-                                    LocalitySortedVersionSet &output_set,
+bool GetLocalitySortedVersionSet(pkgCacheFile &CacheFile,
+                                    APT::VersionContainerInterface * const vci,
                                     Matcher &matcher,
-                                    OpProgress &progress);
-bool GetLocalitySortedVersionSet(pkgCacheFile &CacheFile, 
-                                    LocalitySortedVersionSet &output_set,
-                                    OpProgress &progress);
+                                    OpProgress * const progress);
+bool GetLocalitySortedVersionSet(pkgCacheFile &CacheFile,
+                                    APT::VersionContainerInterface * const vci,
+                                    OpProgress * const progress);
 
 
 // CacheSetHelper saving virtual packages				/*{{{*/
@@ -76,19 +76,16 @@ class CacheSetHelperVirtuals: public APT::CacheSetHelper {
 public:
    APT::PackageSet virtualPkgs;
 
-   virtual pkgCache::VerIterator canNotFindCandidateVer(pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg) {
-      virtualPkgs.insert(Pkg);
-      return CacheSetHelper::canNotFindCandidateVer(Cache, Pkg);
+   virtual pkgCache::VerIterator canNotGetVersion(enum CacheSetHelper::VerSelector const select, pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg) {
+      if (select == NEWEST || select == CANDIDATE || select == ALL)
+	 virtualPkgs.insert(Pkg);
+      return CacheSetHelper::canNotGetVersion(select, Cache, Pkg);
    }
 
-   virtual pkgCache::VerIterator canNotFindNewestVer(pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg) {
-      virtualPkgs.insert(Pkg);
-      return CacheSetHelper::canNotFindNewestVer(Cache, Pkg);
-   }
-
-   virtual void canNotFindAllVer(APT::VersionContainerInterface * vci, pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg) {
-      virtualPkgs.insert(Pkg);
-      CacheSetHelper::canNotFindAllVer(vci, Cache, Pkg);
+   virtual void canNotFindVersion(enum CacheSetHelper::VerSelector const select, APT::VersionContainerInterface * vci, pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg) {
+      if (select == NEWEST || select == CANDIDATE || select == ALL)
+	 virtualPkgs.insert(Pkg);
+      return CacheSetHelper::canNotFindVersion(select, vci, Cache, Pkg);
    }
 
    CacheSetHelperVirtuals(bool const ShowErrors = true, GlobalError::MsgType const &ErrorType = GlobalError::NOTICE) : CacheSetHelper(ShowErrors, ErrorType) {}
@@ -190,7 +187,7 @@ public:
 	}
 
 	virtual pkgCache::VerIterator canNotFindCandidateVer(pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg) {
-		APT::VersionSet const verset = tryVirtualPackage(Cache, Pkg, APT::VersionSet::CANDIDATE);
+		APT::VersionSet const verset = tryVirtualPackage(Cache, Pkg, CacheSetHelper::CANDIDATE);
 		if (verset.empty() == false)
 			return *(verset.begin());
 		else if (ShowError == true) {
@@ -203,7 +200,7 @@ public:
 	virtual pkgCache::VerIterator canNotFindNewestVer(pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg) {
 		if (Pkg->ProvidesList != 0)
 		{
-			APT::VersionSet const verset = tryVirtualPackage(Cache, Pkg, APT::VersionSet::NEWEST);
+			APT::VersionSet const verset = tryVirtualPackage(Cache, Pkg, CacheSetHelper::NEWEST);
 			if (verset.empty() == false)
 				return *(verset.begin());
 			if (ShowError == true)
@@ -231,7 +228,7 @@ public:
 	}
 
 	APT::VersionSet tryVirtualPackage(pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg,
-						APT::VersionSet::Version const &select) {
+						CacheSetHelper::VerSelector const select) {
 		/* This is a pure virtual package and there is a single available
 		   candidate providing it. */
 		if (unlikely(Cache[Pkg].CandidateVer != 0) || Pkg->ProvidesList == 0)

+ 7 - 2
apt-private/private-cmndline.cc

@@ -70,6 +70,8 @@ static bool addArgumentsAPTCache(std::vector<CommandLine::Args> &Args, char cons
    else
       return false;
 
+   bool const found_something = Args.empty() == false;
+
    // FIXME: move to the correct command(s)
    addArg('g', "generate", "APT::Cache::Generate", 0);
    addArg('t', "target-release", "APT::Default-Release", CommandLine::HasArg);
@@ -77,7 +79,8 @@ static bool addArgumentsAPTCache(std::vector<CommandLine::Args> &Args, char cons
 
    addArg('p', "pkg-cache", "Dir::Cache::pkgcache", CommandLine::HasArg);
    addArg('s', "src-cache", "Dir::Cache::srcpkgcache", CommandLine::HasArg);
-   return true;
+
+   return found_something;
 }
 									/*}}}*/
 static bool addArgumentsAPTCDROM(std::vector<CommandLine::Args> &Args, char const * const Cmd)/*{{{*/
@@ -172,6 +175,8 @@ static bool addArgumentsAPTGet(std::vector<CommandLine::Args> &Args, char const
       addArg('s', "no-act", "APT::Get::Simulate", 0);
    }
 
+   bool const found_something = Args.empty() == false;
+
    // FIXME: move to the correct command(s)
    addArg('d',"download-only","APT::Get::Download-Only",0);
    addArg('y',"yes","APT::Get::Assume-Yes",0);
@@ -197,7 +202,7 @@ static bool addArgumentsAPTGet(std::vector<CommandLine::Args> &Args, char const
    addArg(0,"install-suggests","APT::Install-Suggests",CommandLine::Boolean);
    addArg(0,"fix-policy","APT::Get::Fix-Policy-Broken",0);
 
-   return true;
+   return found_something;
 }
 									/*}}}*/
 static bool addArgumentsAPTMark(std::vector<CommandLine::Args> &Args, char const * const Cmd)/*{{{*/

+ 5 - 0
apt-private/private-download.cc

@@ -28,6 +28,11 @@ bool CheckAuth(pkgAcquire& Fetcher, bool const PromptUser)
    if (UntrustedList == "")
       return true;
 
+   return AuthPrompt(UntrustedList, PromptUser);
+}
+
+bool AuthPrompt(std::string UntrustedList, bool const PromptUser)
+{
    ShowList(c2out,_("WARNING: The following packages cannot be authenticated!"),UntrustedList,"");
 
    if (_config->FindB("APT::Get::AllowUnauthenticated",false) == true)

+ 6 - 0
apt-private/private-download.h

@@ -5,7 +5,13 @@
 
 class pkgAcquire;
 
+// Check if all files in the fetcher are authenticated
 APT_PUBLIC bool CheckAuth(pkgAcquire& Fetcher, bool const PromptUser);
+
+// show a authentication warning prompt and return true if the system
+// should continue
+APT_PUBLIC bool AuthPrompt(std::string UntrustedList, bool const PromptUser);
+
 APT_PUBLIC bool AcquireRun(pkgAcquire &Fetcher, int const PulseInterval, bool * const Failure, bool * const TransientNetworkFailure);
 
 #endif

+ 159 - 9
apt-private/private-install.cc

@@ -19,7 +19,7 @@
 #include <apt-pkg/macros.h>
 #include <apt-pkg/packagemanager.h>
 #include <apt-pkg/pkgcache.h>
-#include <apt-pkg/sourcelist.h>
+#include <apt-pkg/upgrade.h>
 #include <apt-pkg/install-progress.h>
 
 #include <errno.h>
@@ -527,15 +527,14 @@ static bool DoAutomaticRemove(CacheFile &Cache)
 static const unsigned short MOD_REMOVE = 1;
 static const unsigned short MOD_INSTALL = 2;
 
-bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, CacheFile &Cache)
+bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, CacheFile &Cache, int UpgradeMode)
 {
    std::map<unsigned short, APT::VersionSet> verset;
-   return DoCacheManipulationFromCommandLine(CmdL, Cache, verset);
+   return DoCacheManipulationFromCommandLine(CmdL, Cache, verset, UpgradeMode);
 }
 bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, CacheFile &Cache,
-                                        std::map<unsigned short, APT::VersionSet> &verset)
+                                        std::map<unsigned short, APT::VersionSet> &verset, int UpgradeMode)
 {
-
    // Enter the special broken fixing mode if the user specified arguments
    bool BrokenFix = false;
    if (Cache->BrokenCount() != 0)
@@ -561,9 +560,9 @@ bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, CacheFile &Cache,
 
    std::list<APT::VersionSet::Modifier> mods;
    mods.push_back(APT::VersionSet::Modifier(MOD_INSTALL, "+",
-		APT::VersionSet::Modifier::POSTFIX, APT::VersionSet::CANDIDATE));
+		APT::VersionSet::Modifier::POSTFIX, APT::CacheSetHelper::CANDIDATE));
    mods.push_back(APT::VersionSet::Modifier(MOD_REMOVE, "-",
-		APT::VersionSet::Modifier::POSTFIX, APT::VersionSet::NEWEST));
+		APT::VersionSet::Modifier::POSTFIX, APT::CacheSetHelper::NEWEST));
    CacheSetHelperAPTGet helper(c0out);
    verset = APT::VersionSet::GroupedFromCommandLine(Cache,
 		CmdL.FileList + 1, mods, fallback, helper);
@@ -620,7 +619,17 @@ bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, CacheFile &Cache,
       if (Fix != NULL)
       {
 	 // Call the scored problem resolver
-	 Fix->Resolve(true);
+	 OpTextProgress Progress(*_config);
+	 bool const distUpgradeMode = strcmp(CmdL.FileList[0], "dist-upgrade") == 0 || strcmp(CmdL.FileList[0], "full-upgrade") == 0;
+
+	 bool resolver_fail = false;
+	 if (distUpgradeMode == true || UpgradeMode != APT::Upgrade::ALLOW_EVERYTHING)
+	    resolver_fail = APT::Upgrade::Upgrade(Cache, UpgradeMode, &Progress);
+	 else
+	    resolver_fail = Fix->Resolve(true, &Progress);
+
+	 if (resolver_fail == false && Cache->BrokenCount() == 0)
+	    return false;
       }
 
       // Now we check the state of the packages,
@@ -702,7 +711,7 @@ bool DoInstall(CommandLine &CmdL)
    
    std::map<unsigned short, APT::VersionSet> verset;
 
-   if(!DoCacheManipulationFromCommandLine(CmdL, Cache, verset))
+   if(!DoCacheManipulationFromCommandLine(CmdL, Cache, verset, 0))
       return false;
 
    /* Print out a list of packages that are going to be installed extra
@@ -828,3 +837,144 @@ bool DoInstall(CommandLine &CmdL)
    return InstallPackages(Cache,false);   
 }
 									/*}}}*/
+
+// TryToInstall - Mark a package for installation			/*{{{*/
+void TryToInstall::operator() (pkgCache::VerIterator const &Ver) {
+   pkgCache::PkgIterator Pkg = Ver.ParentPkg();
+
+   Cache->GetDepCache()->SetCandidateVersion(Ver);
+   pkgDepCache::StateCache &State = (*Cache)[Pkg];
+
+   // Handle the no-upgrade case
+   if (_config->FindB("APT::Get::upgrade",true) == false && Pkg->CurrentVer != 0)
+      ioprintf(c1out,_("Skipping %s, it is already installed and upgrade is not set.\n"),
+	    Pkg.FullName(true).c_str());
+   // Ignore request for install if package would be new
+   else if (_config->FindB("APT::Get::Only-Upgrade", false) == true && Pkg->CurrentVer == 0)
+      ioprintf(c1out,_("Skipping %s, it is not installed and only upgrades are requested.\n"),
+	    Pkg.FullName(true).c_str());
+   else {
+      if (Fix != NULL) {
+	 Fix->Clear(Pkg);
+	 Fix->Protect(Pkg);
+      }
+      Cache->GetDepCache()->MarkInstall(Pkg,false);
+
+      if (State.Install() == false) {
+	 if (_config->FindB("APT::Get::ReInstall",false) == true) {
+	    if (Pkg->CurrentVer == 0 || Pkg.CurrentVer().Downloadable() == false)
+	       ioprintf(c1out,_("Reinstallation of %s is not possible, it cannot be downloaded.\n"),
+		     Pkg.FullName(true).c_str());
+	    else
+	       Cache->GetDepCache()->SetReInstall(Pkg, true);
+	 } else
+	    ioprintf(c1out,_("%s is already the newest version.\n"),
+		  Pkg.FullName(true).c_str());
+      }
+
+      // Install it with autoinstalling enabled (if we not respect the minial
+      // required deps or the policy)
+      if (FixBroken == false)
+	 doAutoInstallLater.insert(Pkg);
+   }
+
+   // see if we need to fix the auto-mark flag
+   // e.g. apt-get install foo
+   // where foo is marked automatic
+   if (State.Install() == false &&
+	 (State.Flags & pkgCache::Flag::Auto) &&
+	 _config->FindB("APT::Get::ReInstall",false) == false &&
+	 _config->FindB("APT::Get::Only-Upgrade",false) == false &&
+	 _config->FindB("APT::Get::Download-Only",false) == false)
+   {
+      ioprintf(c1out,_("%s set to manually installed.\n"),
+	    Pkg.FullName(true).c_str());
+      Cache->GetDepCache()->MarkAuto(Pkg,false);
+      AutoMarkChanged++;
+   }
+}
+									/*}}}*/
+bool TryToInstall::propergateReleaseCandiateSwitching(std::list<std::pair<pkgCache::VerIterator, std::string> > const &start, std::ostream &out)/*{{{*/
+{
+   for (std::list<std::pair<pkgCache::VerIterator, std::string> >::const_iterator s = start.begin();
+	 s != start.end(); ++s)
+      Cache->GetDepCache()->SetCandidateVersion(s->first);
+
+   bool Success = true;
+   // the Changed list contains:
+   //   first: "new version"
+   //   second: "what-caused the change"
+   std::list<std::pair<pkgCache::VerIterator, pkgCache::VerIterator> > Changed;
+   for (std::list<std::pair<pkgCache::VerIterator, std::string> >::const_iterator s = start.begin();
+	 s != start.end(); ++s)
+   {
+      Changed.push_back(std::make_pair(s->first, pkgCache::VerIterator(*Cache)));
+      // We continue here even if it failed to enhance the ShowBroken output
+      Success &= Cache->GetDepCache()->SetCandidateRelease(s->first, s->second, Changed);
+   }
+   for (std::list<std::pair<pkgCache::VerIterator, pkgCache::VerIterator> >::const_iterator c = Changed.begin();
+	 c != Changed.end(); ++c)
+   {
+      if (c->second.end() == true)
+	 ioprintf(out, _("Selected version '%s' (%s) for '%s'\n"),
+	       c->first.VerStr(), c->first.RelStr().c_str(), c->first.ParentPkg().FullName(true).c_str());
+      else if (c->first.ParentPkg()->Group != c->second.ParentPkg()->Group)
+      {
+	 pkgCache::VerIterator V = (*Cache)[c->first.ParentPkg()].CandidateVerIter(*Cache);
+	 ioprintf(out, _("Selected version '%s' (%s) for '%s' because of '%s'\n"), V.VerStr(),
+	       V.RelStr().c_str(), V.ParentPkg().FullName(true).c_str(), c->second.ParentPkg().FullName(true).c_str());
+      }
+   }
+   return Success;
+}
+									/*}}}*/
+void TryToInstall::doAutoInstall() {					/*{{{*/
+   for (APT::PackageSet::const_iterator P = doAutoInstallLater.begin();
+	 P != doAutoInstallLater.end(); ++P) {
+      pkgDepCache::StateCache &State = (*Cache)[P];
+      if (State.InstBroken() == false && State.InstPolicyBroken() == false)
+	 continue;
+      Cache->GetDepCache()->MarkInstall(P, true);
+   }
+   doAutoInstallLater.clear();
+}
+									/*}}}*/
+// TryToRemove - Mark a package for removal				/*{{{*/
+void TryToRemove::operator() (pkgCache::VerIterator const &Ver)
+{
+   pkgCache::PkgIterator Pkg = Ver.ParentPkg();
+
+   if (Fix != NULL)
+   {
+      Fix->Clear(Pkg);
+      Fix->Protect(Pkg);
+      Fix->Remove(Pkg);
+   }
+
+   if ((Pkg->CurrentVer == 0 && PurgePkgs == false) ||
+	 (PurgePkgs == true && Pkg->CurrentState == pkgCache::State::NotInstalled))
+   {
+      pkgCache::GrpIterator Grp = Pkg.Group();
+      pkgCache::PkgIterator P = Grp.PackageList();
+      for (; P.end() != true; P = Grp.NextPkg(P))
+      {
+	 if (P == Pkg)
+	    continue;
+	 if (P->CurrentVer != 0 || (PurgePkgs == true && P->CurrentState != pkgCache::State::NotInstalled))
+	 {
+	    // TRANSLATORS: Note, this is not an interactive question
+	    ioprintf(c1out,_("Package '%s' is not installed, so not removed. Did you mean '%s'?\n"),
+		  Pkg.FullName(true).c_str(), P.FullName(true).c_str());
+	    break;
+	 }
+      }
+      if (P.end() == true)
+	 ioprintf(c1out,_("Package '%s' is not installed, so not removed\n"),Pkg.FullName(true).c_str());
+
+      // MarkInstall refuses to install packages on hold
+      Pkg->SelectedState = pkgCache::State::Hold;
+   }
+   else
+      Cache->GetDepCache()->MarkDelete(Pkg, PurgePkgs);
+}
+									/*}}}*/

+ 9 - 151
apt-private/private-install.h

@@ -3,43 +3,33 @@
 
 #include <apt-pkg/cachefile.h>
 #include <apt-pkg/configuration.h>
-#include <apt-pkg/depcache.h>
 #include <apt-pkg/pkgcache.h>
 #include <apt-pkg/cacheiterators.h>
 #include <apt-pkg/cacheset.h>
-#include <apt-pkg/strutl.h>
-#include <apt-pkg/algorithms.h>
 #include <apt-pkg/macros.h>
 
-#include <apt-private/private-output.h>
-
-#include <stddef.h>
-#include <iosfwd>
 #include <list>
-#include <map>
 #include <string>
 #include <utility>
 
-
-#include <apti18n.h>
-
 class CacheFile;
 class CommandLine;
+class pkgProblemResolver;
 
 #define RAMFS_MAGIC     0x858458f6
 
 APT_PUBLIC bool DoInstall(CommandLine &Cmd);
 
 bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, CacheFile &Cache,
-                                        std::map<unsigned short, APT::VersionSet> &verset);
-bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, CacheFile &Cache);
+                                        std::map<unsigned short, APT::VersionSet> &verset, int UpgradeMode);
+bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, CacheFile &Cache, int UpgradeMode);
 
 APT_PUBLIC bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true,
                         bool Safety = true);
 
 
 // TryToInstall - Mark a package for installation			/*{{{*/
-struct TryToInstall {
+struct APT_PUBLIC TryToInstall {
    pkgCacheFile* Cache;
    pkgProblemResolver* Fix;
    bool FixBroken;
@@ -49,109 +39,13 @@ struct TryToInstall {
    TryToInstall(pkgCacheFile &Cache, pkgProblemResolver *PM, bool const FixBroken) : Cache(&Cache), Fix(PM),
 			FixBroken(FixBroken), AutoMarkChanged(0) {};
 
-   void operator() (pkgCache::VerIterator const &Ver) {
-      pkgCache::PkgIterator Pkg = Ver.ParentPkg();
-
-      Cache->GetDepCache()->SetCandidateVersion(Ver);
-      pkgDepCache::StateCache &State = (*Cache)[Pkg];
-
-      // Handle the no-upgrade case
-      if (_config->FindB("APT::Get::upgrade",true) == false && Pkg->CurrentVer != 0)
-	 ioprintf(c1out,_("Skipping %s, it is already installed and upgrade is not set.\n"),
-		  Pkg.FullName(true).c_str());
-      // Ignore request for install if package would be new
-      else if (_config->FindB("APT::Get::Only-Upgrade", false) == true && Pkg->CurrentVer == 0)
-	 ioprintf(c1out,_("Skipping %s, it is not installed and only upgrades are requested.\n"),
-		  Pkg.FullName(true).c_str());
-      else {
-	 if (Fix != NULL) {
-	    Fix->Clear(Pkg);
-	    Fix->Protect(Pkg);
-	 }
-	 Cache->GetDepCache()->MarkInstall(Pkg,false);
-
-	 if (State.Install() == false) {
-	    if (_config->FindB("APT::Get::ReInstall",false) == true) {
-	       if (Pkg->CurrentVer == 0 || Pkg.CurrentVer().Downloadable() == false)
-		  ioprintf(c1out,_("Reinstallation of %s is not possible, it cannot be downloaded.\n"),
-			   Pkg.FullName(true).c_str());
-	       else
-		  Cache->GetDepCache()->SetReInstall(Pkg, true);
-	    } else
-	       ioprintf(c1out,_("%s is already the newest version.\n"),
-			Pkg.FullName(true).c_str());
-	 }
-
-	 // Install it with autoinstalling enabled (if we not respect the minial
-	 // required deps or the policy)
-	 if (FixBroken == false)
-	    doAutoInstallLater.insert(Pkg);
-      }
-
-      // see if we need to fix the auto-mark flag
-      // e.g. apt-get install foo
-      // where foo is marked automatic
-      if (State.Install() == false &&
-	  (State.Flags & pkgCache::Flag::Auto) &&
-	  _config->FindB("APT::Get::ReInstall",false) == false &&
-	  _config->FindB("APT::Get::Only-Upgrade",false) == false &&
-	  _config->FindB("APT::Get::Download-Only",false) == false)
-      {
-	 ioprintf(c1out,_("%s set to manually installed.\n"),
-		  Pkg.FullName(true).c_str());
-	 Cache->GetDepCache()->MarkAuto(Pkg,false);
-	 AutoMarkChanged++;
-      }
-   }
-
-   bool propergateReleaseCandiateSwitching(std::list<std::pair<pkgCache::VerIterator, std::string> > start, std::ostream &out)
-   {
-      for (std::list<std::pair<pkgCache::VerIterator, std::string> >::const_iterator s = start.begin();
-		s != start.end(); ++s)
-	 Cache->GetDepCache()->SetCandidateVersion(s->first);
-
-      bool Success = true;
-      // the Changed list contains:
-      //   first: "new version" 
-      //   second: "what-caused the change" 
-      std::list<std::pair<pkgCache::VerIterator, pkgCache::VerIterator> > Changed;
-      for (std::list<std::pair<pkgCache::VerIterator, std::string> >::const_iterator s = start.begin();
-		s != start.end(); ++s)
-      {
-	 Changed.push_back(std::make_pair(s->first, pkgCache::VerIterator(*Cache)));
-	 // We continue here even if it failed to enhance the ShowBroken output
-	 Success &= Cache->GetDepCache()->SetCandidateRelease(s->first, s->second, Changed);
-      }
-      for (std::list<std::pair<pkgCache::VerIterator, pkgCache::VerIterator> >::const_iterator c = Changed.begin();
-	   c != Changed.end(); ++c)
-      {
-	 if (c->second.end() == true)
-	    ioprintf(out, _("Selected version '%s' (%s) for '%s'\n"),
-		     c->first.VerStr(), c->first.RelStr().c_str(), c->first.ParentPkg().FullName(true).c_str());
-	 else if (c->first.ParentPkg()->Group != c->second.ParentPkg()->Group)
-	 {
-	    pkgCache::VerIterator V = (*Cache)[c->first.ParentPkg()].CandidateVerIter(*Cache);
-	    ioprintf(out, _("Selected version '%s' (%s) for '%s' because of '%s'\n"), V.VerStr(),
-		     V.RelStr().c_str(), V.ParentPkg().FullName(true).c_str(), c->second.ParentPkg().FullName(true).c_str());
-	 }
-      }
-      return Success;
-   }
-
-   void doAutoInstall() {
-      for (APT::PackageSet::const_iterator P = doAutoInstallLater.begin();
-	   P != doAutoInstallLater.end(); ++P) {
-	 pkgDepCache::StateCache &State = (*Cache)[P];
-	 if (State.InstBroken() == false && State.InstPolicyBroken() == false)
-	    continue;
-	 Cache->GetDepCache()->MarkInstall(P, true);
-      }
-      doAutoInstallLater.clear();
-   }
+   void operator() (pkgCache::VerIterator const &Ver);
+   bool propergateReleaseCandiateSwitching(std::list<std::pair<pkgCache::VerIterator, std::string> > const &start, std::ostream &out);
+   void doAutoInstall();
 };
 									/*}}}*/
 // TryToRemove - Mark a package for removal				/*{{{*/
-struct TryToRemove {
+struct APT_PUBLIC TryToRemove {
    pkgCacheFile* Cache;
    pkgProblemResolver* Fix;
    bool PurgePkgs;
@@ -159,43 +53,7 @@ struct TryToRemove {
    TryToRemove(pkgCacheFile &Cache, pkgProblemResolver *PM) : Cache(&Cache), Fix(PM),
 				PurgePkgs(_config->FindB("APT::Get::Purge", false)) {};
 
-   void operator() (pkgCache::VerIterator const &Ver)
-   {
-      pkgCache::PkgIterator Pkg = Ver.ParentPkg();
-
-      if (Fix != NULL)
-      {
-	 Fix->Clear(Pkg);
-	 Fix->Protect(Pkg);
-	 Fix->Remove(Pkg);
-      }
-
-      if ((Pkg->CurrentVer == 0 && PurgePkgs == false) ||
-	  (PurgePkgs == true && Pkg->CurrentState == pkgCache::State::NotInstalled))
-      {
-	 pkgCache::GrpIterator Grp = Pkg.Group();
-	 pkgCache::PkgIterator P = Grp.PackageList();
-	 for (; P.end() != true; P = Grp.NextPkg(P))
-	 {
-	    if (P == Pkg)
-	       continue;
-	    if (P->CurrentVer != 0 || (PurgePkgs == true && P->CurrentState != pkgCache::State::NotInstalled))
-	    {
-	       // TRANSLATORS: Note, this is not an interactive question
-	       ioprintf(c1out,_("Package '%s' is not installed, so not removed. Did you mean '%s'?\n"),
-			Pkg.FullName(true).c_str(), P.FullName(true).c_str());
-	       break;
-	    }
-	 }
-	 if (P.end() == true)
-	    ioprintf(c1out,_("Package '%s' is not installed, so not removed\n"),Pkg.FullName(true).c_str());
-
-	 // MarkInstall refuses to install packages on hold
-	 Pkg->SelectedState = pkgCache::State::Hold;
-      }
-      else
-	 Cache->GetDepCache()->MarkDelete(Pkg, PurgePkgs);
-   }
+   void operator() (pkgCache::VerIterator const &Ver);
 };
 									/*}}}*/
 

+ 18 - 23
apt-private/private-list.cc

@@ -77,15 +77,14 @@ private:
 };
 									/*}}}*/
 static void ListAllVersions(pkgCacheFile &CacheFile, pkgRecords &records,/*{{{*/
-                     pkgCache::PkgIterator P,    
-                     std::ostream &outs,
-                     bool include_summary=true)
+                     pkgCache::PkgIterator const &P, std::ostream &outs,
+                     std::string const &format)
 {
    for (pkgCache::VerIterator Ver = P.VersionList();
         Ver.end() == false; ++Ver)
    {
-      ListSingleVersion(CacheFile, records, Ver, outs, include_summary);
-      outs << "\n";
+      ListSingleVersion(CacheFile, records, Ver, outs, format);
+      outs << std::endl;
    }
 }
 									/*}}}*/
@@ -109,10 +108,9 @@ bool DoList(CommandLine &Cmd)
       patterns = Cmd.FileList + 1;
    }
 
-   std::map<std::string, std::string> output_map;
-   std::map<std::string, std::string>::const_iterator K;
-
-   bool includeSummary = _config->FindB("APT::Cmd::List-Include-Summary");
+   std::string format = "${color:highlight}${Package}${color:neutral}/${Origin} ${Version} ${Architecture}${ }${apt:Status}";
+   if (_config->FindB("APT::Cmd::List-Include-Summary", false) == true)
+      format += "\n  ${Description}\n";
 
    PackageNameMatcher matcher(patterns);
    LocalitySortedVersionSet bag;
@@ -121,37 +119,34 @@ bool DoList(CommandLine &Cmd)
                             Cache->Head().PackageCount, 
                             Cache->Head().PackageCount,
                             _("Listing"));
-   GetLocalitySortedVersionSet(CacheFile, bag, matcher, progress);
-   bool ShowAllVersions = _config->FindB("APT::Cmd::All-Versions", false);
+   GetLocalitySortedVersionSet(CacheFile, &bag, matcher, &progress);
+   bool const ShowAllVersions = _config->FindB("APT::Cmd::All-Versions", false);
+   std::map<std::string, std::string> output_map;
    for (LocalitySortedVersionSet::iterator V = bag.begin(); V != bag.end(); ++V)
    {
       std::stringstream outs;
       if(ShowAllVersions == true)
-      {
-         ListAllVersions(CacheFile, records, V.ParentPkg(), outs, includeSummary);
-         output_map.insert(std::make_pair<std::string, std::string>(
-            V.ParentPkg().Name(), outs.str()));
-      } else {
-         ListSingleVersion(CacheFile, records, V, outs, includeSummary);
-         output_map.insert(std::make_pair<std::string, std::string>(
-                           V.ParentPkg().Name(), outs.str()));
-      }
+         ListAllVersions(CacheFile, records, V.ParentPkg(), outs, format);
+      else
+         ListSingleVersion(CacheFile, records, V, outs, format);
+      output_map.insert(std::make_pair<std::string, std::string>(
+	       V.ParentPkg().Name(), outs.str()));
    }
 
    // FIXME: SORT! and make sorting flexible (alphabetic, by pkg status)
    // output the sorted map
+   std::map<std::string, std::string>::const_iterator K;
    for (K = output_map.begin(); K != output_map.end(); ++K)
       std::cout << (*K).second << std::endl;
 
-
    // be nice and tell the user if there is more to see
    if (bag.size() == 1 && ShowAllVersions == false)
    {
       // start with -1 as we already displayed one version
       int versions = -1;
       pkgCache::VerIterator Ver = *bag.begin();
-      for ( ; Ver.end() == false; Ver++)
-         versions++;
+      for ( ; Ver.end() == false; ++Ver)
+         ++versions;
       if (versions > 0)
          _error->Notice(P_("There is %i additional version. Please use the '-a' switch to see it", "There are %i additional versions. Please use the '-a' switch to see them.", versions), versions);
    }

+ 205 - 172
apt-private/private-output.cc

@@ -94,7 +94,7 @@ bool InitOutput()							/*{{{*/
 static std::string GetArchiveSuite(pkgCacheFile &/*CacheFile*/, pkgCache::VerIterator ver) /*{{{*/
 {
    std::string suite = "";
-   if (ver && ver.FileList() && ver.FileList())
+   if (ver && ver.FileList())
    {
       pkgCache::VerFileIterator VF = ver.FileList();
       for (; VF.end() == false ; ++VF)
@@ -118,7 +118,7 @@ static std::string GetFlagsStr(pkgCacheFile &CacheFile, pkgCache::PkgIterator P)
    std::string flags_str;
    if (state.NowBroken())
       flags_str = "B";
-   if (P.CurrentVer() && state.Upgradable())
+   if (P.CurrentVer() && state.Upgradable() && state.CandidateVer != NULL)
       flags_str = "g";
    else if (P.CurrentVer() != NULL)
       flags_str = "i";
@@ -164,15 +164,26 @@ static std::string GetVersion(pkgCacheFile &/*CacheFile*/, pkgCache::VerIterator
 									/*}}}*/
 static std::string GetArchitecture(pkgCacheFile &CacheFile, pkgCache::PkgIterator P)/*{{{*/
 {
-   pkgPolicy *policy = CacheFile.GetPolicy();
-   pkgCache::VerIterator inst = P.CurrentVer();
-   pkgCache::VerIterator cand = policy->GetCandidateVer(P);
-
-   // this may happen for packages in dpkg "deinstall ok config-file" state
-   if (inst.IsGood() == false && cand.IsGood() == false)
-      return P.VersionList().Arch();
-
-   return inst ? inst.Arch() : cand.Arch();
+   if (P->CurrentVer == 0)
+   {
+      pkgDepCache * const DepCache = CacheFile.GetDepCache();
+      pkgDepCache::StateCache const &state = (*DepCache)[P];
+      if (state.CandidateVer != NULL)
+      {
+	 pkgCache::VerIterator const CandV(CacheFile, state.CandidateVer);
+	 return CandV.Arch();
+      }
+      else
+      {
+	 pkgCache::VerIterator const V = P.VersionList();
+	 if (V.end() == false)
+	    return V.Arch();
+	 else
+	    return P.Arch();
+      }
+   }
+   else
+      return P.CurrentVer().Arch();
 }
 									/*}}}*/
 static std::string GetShortDescription(pkgCacheFile &CacheFile, pkgRecords &records, pkgCache::PkgIterator P)/*{{{*/
@@ -196,80 +207,90 @@ static std::string GetShortDescription(pkgCacheFile &CacheFile, pkgRecords &reco
    return ShortDescription;
 }
 									/*}}}*/
-void ListSingleVersion(pkgCacheFile &CacheFile, pkgRecords &records,	/*{{{*/
-                       pkgCache::VerIterator V, std::ostream &out,
-                       bool include_summary)
+static std::string GetLongDescription(pkgCacheFile &CacheFile, pkgRecords &records, pkgCache::PkgIterator P)/*{{{*/
 {
-   pkgCache::PkgIterator P = V.ParentPkg();
+   pkgPolicy *policy = CacheFile.GetPolicy();
 
-   pkgDepCache *DepCache = CacheFile.GetDepCache();
-   pkgDepCache::StateCache &state = (*DepCache)[P];
+   pkgCache::VerIterator ver;
+   if (P->CurrentVer != 0)
+      ver = P.CurrentVer();
+   else
+      ver = policy->GetCandidateVer(P);
 
-   std::string suite = GetArchiveSuite(CacheFile, V);
-   std::string name_str = P.Name();
+   std::string const EmptyDescription = "(none)";
+   if(ver.end() == true)
+      return EmptyDescription;
+
+   pkgCache::DescIterator const Desc = ver.TranslatedDescription();
+   pkgRecords::Parser & parser = records.Lookup(Desc.FileList());
+   std::string const longdesc = parser.LongDesc();
+   if (longdesc.empty() == true)
+      return EmptyDescription;
+   return SubstVar(longdesc, "\n ", "\n  ");
+}
+									/*}}}*/
+void ListSingleVersion(pkgCacheFile &CacheFile, pkgRecords &records,	/*{{{*/
+                       pkgCache::VerIterator const &V, std::ostream &out,
+                       std::string const &format)
+{
+   pkgCache::PkgIterator const P = V.ParentPkg();
+   pkgDepCache * const DepCache = CacheFile.GetDepCache();
+   pkgDepCache::StateCache const &state = (*DepCache)[P];
 
+   std::string output;
    if (_config->FindB("APT::Cmd::use-format", false))
+      output = _config->Find("APT::Cmd::format", "${db::Status-Abbrev} ${Package} ${Version} ${Origin} ${Description}");
+   else
+      output = format;
+
+   // FIXME: some of these names are really icky – and all is nowhere documented
+   output = SubstVar(output, "${db::Status-Abbrev}", GetFlagsStr(CacheFile, P));
+   output = SubstVar(output, "${Package}", P.Name());
+   std::string const ArchStr = GetArchitecture(CacheFile, P);
+   output = SubstVar(output, "${Architecture}", ArchStr);
+   std::string const InstalledVerStr = GetInstalledVersion(CacheFile, P);
+   output = SubstVar(output, "${installed:Version}", InstalledVerStr);
+   std::string const CandidateVerStr = GetCandidateVersion(CacheFile, P);
+   output = SubstVar(output, "${candidate:Version}", CandidateVerStr);
+   std::string const VersionStr = GetVersion(CacheFile, V);
+   output = SubstVar(output, "${Version}", VersionStr);
+   output = SubstVar(output, "${Origin}", GetArchiveSuite(CacheFile, V));
+
+   std::string StatusStr = "";
+   if (P->CurrentVer != 0)
    {
-      std::string format = _config->Find("APT::Cmd::format", "${db::Status-Abbrev} ${Package} ${Version} ${Origin} ${Description}");
-      std::string output = format;
-   
-      output = SubstVar(output, "${db::Status-Abbrev}", GetFlagsStr(CacheFile, P));
-      output = SubstVar(output, "${Package}", name_str);
-      output = SubstVar(output, "${installed:Version}", GetInstalledVersion(CacheFile, P));
-      output = SubstVar(output, "${candidate:Version}", GetCandidateVersion(CacheFile, P));
-      output = SubstVar(output, "${Version}", GetVersion(CacheFile, V));
-      output = SubstVar(output, "${Description}", GetShortDescription(CacheFile, records, P));
-      output = SubstVar(output, "${Origin}", GetArchiveSuite(CacheFile, V));
-      out << output << std::endl;
-   } else {
-      // raring/linux-kernel version [upradable: new-version]
-      //    description
-      pkgPolicy *policy = CacheFile.GetPolicy();
-      std::string VersionStr = GetVersion(CacheFile, V);
-      std::string CandidateVerStr = GetCandidateVersion(CacheFile, P);
-      std::string InstalledVerStr = GetInstalledVersion(CacheFile, P);
-      std::string StatusStr;
-      if(P.CurrentVer() == V && state.Upgradable()) {
-         strprintf(StatusStr, _("[installed,upgradable to: %s]"),
-                   CandidateVerStr.c_str());
-      } else if (P.CurrentVer() == V) {
-         if(!V.Downloadable())
-            StatusStr = _("[installed,local]");
-         else
-            if(V.Automatic() && state.Garbage)
-               StatusStr = _("[installed,auto-removable]");
-            else if (state.Flags & pkgCache::Flag::Auto)
-               StatusStr = _("[installed,automatic]");
-            else
-               StatusStr = _("[installed]");
-      } else if (P.CurrentVer() && 
-                 policy->GetCandidateVer(P) == V && 
-                 state.Upgradable()) {
-            strprintf(StatusStr, _("[upgradable from: %s]"),
-                      InstalledVerStr.c_str());
-      } else {
-         if (V.ParentPkg()->CurrentState == pkgCache::State::ConfigFiles)
-            StatusStr = _("[residual-config]");
-         else
-            StatusStr = "";
-      }
-      out << std::setiosflags(std::ios::left)
-          << _config->Find("APT::Color::Highlight", "")
-          << name_str 
-          << _config->Find("APT::Color::Neutral", "")
-          << "/" << suite
-          << " "
-          << VersionStr << " " 
-          << GetArchitecture(CacheFile, P);
-      if (StatusStr != "") 
-         out << " " << StatusStr;
-      if (include_summary)
+      if (P.CurrentVer() == V)
       {
-         out << std::endl 
-             << "  " << GetShortDescription(CacheFile, records, P)
-             << std::endl;
+	 if (state.Upgradable() && state.CandidateVer != NULL)
+	    strprintf(StatusStr, _("[installed,upgradable to: %s]"),
+		  CandidateVerStr.c_str());
+	 else if (V.Downloadable() == false)
+	    StatusStr = _("[installed,local]");
+	 else if(V.Automatic() == true && state.Garbage == true)
+	    StatusStr = _("[installed,auto-removable]");
+	 else if ((state.Flags & pkgCache::Flag::Auto) == pkgCache::Flag::Auto)
+	    StatusStr = _("[installed,automatic]");
+	 else
+	    StatusStr = _("[installed]");
       }
+      else if (state.CandidateVer == V && state.Upgradable())
+	 strprintf(StatusStr, _("[upgradable from: %s]"),
+	       InstalledVerStr.c_str());
    }
+   else if (V.ParentPkg()->CurrentState == pkgCache::State::ConfigFiles)
+      StatusStr = _("[residual-config]");
+   output = SubstVar(output, "${apt:Status}", StatusStr);
+   output = SubstVar(output, "${color:highlight}", _config->Find("APT::Color::Highlight", ""));
+   output = SubstVar(output, "${color:neutral}", _config->Find("APT::Color::Neutral", ""));
+   output = SubstVar(output, "${Description}", GetShortDescription(CacheFile, records, P));
+   output = SubstVar(output, "${LongDescription}", GetLongDescription(CacheFile, records, P));
+   output = SubstVar(output, "${ }${ }", "${ }");
+   output = SubstVar(output, "${ }\n", "\n");
+   output = SubstVar(output, "${ }", " ");
+   if (APT::String::Endswith(output, " ") == true)
+      output.erase(output.length() - 1);
+
+   out << output;
 }
 									/*}}}*/
 // ShowList - Show a list						/*{{{*/
@@ -344,129 +365,141 @@ bool ShowList(ostream &out,string Title,string List,string VersionsList)
            Depends: libldap2 (>= 2.0.2-2) but it is not going to be installed
            Depends: libsasl7 but it is not going to be installed   
  */
-void ShowBroken(ostream &out,CacheFile &Cache,bool Now)
+static void ShowBrokenPackage(ostream &out, pkgCacheFile * const Cache, pkgCache::PkgIterator const &Pkg, bool const Now)
 {
-   if (Cache->BrokenCount() == 0)
+   if (Now == true)
+   {
+      if ((*Cache)[Pkg].NowBroken() == false)
+	 return;
+   }
+   else
+   {
+      if ((*Cache)[Pkg].InstBroken() == false)
+	 return;
+   }
+
+   // Print out each package and the failed dependencies
+   out << " " << Pkg.FullName(true) << " :";
+   unsigned const Indent = Pkg.FullName(true).size() + 3;
+   bool First = true;
+   pkgCache::VerIterator Ver;
+
+   if (Now == true)
+      Ver = Pkg.CurrentVer();
+   else
+      Ver = (*Cache)[Pkg].InstVerIter(*Cache);
+
+   if (Ver.end() == true)
+   {
+      out << endl;
       return;
+   }
 
-   out << _("The following packages have unmet dependencies:") << endl;
-   for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
+   for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false;)
    {
-      pkgCache::PkgIterator I(Cache,Cache.List[J]);
-      
+      // Compute a single dependency element (glob or)
+      pkgCache::DepIterator Start;
+      pkgCache::DepIterator End;
+      D.GlobOr(Start,End); // advances D
+
+      if ((*Cache)->IsImportantDep(End) == false)
+	 continue;
+
       if (Now == true)
       {
-	 if (Cache[I].NowBroken() == false)
+	 if (((*Cache)[End] & pkgDepCache::DepGNow) == pkgDepCache::DepGNow)
 	    continue;
       }
       else
       {
-	 if (Cache[I].InstBroken() == false)
+	 if (((*Cache)[End] & pkgDepCache::DepGInstall) == pkgDepCache::DepGInstall)
 	    continue;
       }
-      
-      // Print out each package and the failed dependencies
-      out << " " << I.FullName(true) << " :";
-      unsigned const Indent = I.FullName(true).size() + 3;
-      bool First = true;
-      pkgCache::VerIterator Ver;
-      
-      if (Now == true)
-	 Ver = I.CurrentVer();
-      else
-	 Ver = Cache[I].InstVerIter(Cache);
-      
-      if (Ver.end() == true)
-      {
-	 out << endl;
-	 continue;
-      }
-      
-      for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false;)
+
+      bool FirstOr = true;
+      while (1)
       {
-	 // Compute a single dependency element (glob or)
-	 pkgCache::DepIterator Start;
-	 pkgCache::DepIterator End;
-	 D.GlobOr(Start,End); // advances D
+	 if (First == false)
+	    for (unsigned J = 0; J != Indent; J++)
+	       out << ' ';
+	 First = false;
 
-	 if (Cache->IsImportantDep(End) == false)
-	    continue;
-	 
-	 if (Now == true)
+	 if (FirstOr == false)
 	 {
-	    if ((Cache[End] & pkgDepCache::DepGNow) == pkgDepCache::DepGNow)
-	       continue;
+	    for (unsigned J = 0; J != strlen(End.DepType()) + 3; J++)
+	       out << ' ';
 	 }
 	 else
+	    out << ' ' << End.DepType() << ": ";
+	 FirstOr = false;
+
+	 out << Start.TargetPkg().FullName(true);
+
+	 // Show a quick summary of the version requirements
+	 if (Start.TargetVer() != 0)
+	    out << " (" << Start.CompType() << " " << Start.TargetVer() << ")";
+
+	 /* Show a summary of the target package if possible. In the case
+	    of virtual packages we show nothing */
+	 pkgCache::PkgIterator Targ = Start.TargetPkg();
+	 if (Targ->ProvidesList == 0)
 	 {
-	    if ((Cache[End] & pkgDepCache::DepGInstall) == pkgDepCache::DepGInstall)
-	       continue;
-	 }
-	 
-	 bool FirstOr = true;
-	 while (1)
-	 {
-	    if (First == false)
-	       for (unsigned J = 0; J != Indent; J++)
-		  out << ' ';
-	    First = false;
+	    out << ' ';
+	    pkgCache::VerIterator Ver = (*Cache)[Targ].InstVerIter(*Cache);
+	    if (Now == true)
+	       Ver = Targ.CurrentVer();
 
-	    if (FirstOr == false)
+	    if (Ver.end() == false)
 	    {
-	       for (unsigned J = 0; J != strlen(End.DepType()) + 3; J++)
-		  out << ' ';
+	       if (Now == true)
+		  ioprintf(out,_("but %s is installed"),Ver.VerStr());
+	       else
+		  ioprintf(out,_("but %s is to be installed"),Ver.VerStr());
 	    }
 	    else
-	       out << ' ' << End.DepType() << ": ";
-	    FirstOr = false;
-	    
-	    out << Start.TargetPkg().FullName(true);
-	 
-	    // Show a quick summary of the version requirements
-	    if (Start.TargetVer() != 0)
-	       out << " (" << Start.CompType() << " " << Start.TargetVer() << ")";
-	    
-	    /* Show a summary of the target package if possible. In the case
-	       of virtual packages we show nothing */	 
-	    pkgCache::PkgIterator Targ = Start.TargetPkg();
-	    if (Targ->ProvidesList == 0)
 	    {
-	       out << ' ';
-	       pkgCache::VerIterator Ver = Cache[Targ].InstVerIter(Cache);
-	       if (Now == true)
-		  Ver = Targ.CurrentVer();
-	       	    
-	       if (Ver.end() == false)
+	       if ((*Cache)[Targ].CandidateVerIter(*Cache).end() == true)
 	       {
-		  if (Now == true)
-		     ioprintf(out,_("but %s is installed"),Ver.VerStr());
+		  if (Targ->ProvidesList == 0)
+		     out << _("but it is not installable");
 		  else
-		     ioprintf(out,_("but %s is to be installed"),Ver.VerStr());
-	       }	       
+		     out << _("but it is a virtual package");
+	       }
 	       else
-	       {
-		  if (Cache[Targ].CandidateVerIter(Cache).end() == true)
-		  {
-		     if (Targ->ProvidesList == 0)
-			out << _("but it is not installable");
-		     else
-			out << _("but it is a virtual package");
-		  }		  
-		  else
-		     out << (Now?_("but it is not installed"):_("but it is not going to be installed"));
-	       }	       
+		  out << (Now?_("but it is not installed"):_("but it is not going to be installed"));
 	    }
-	    
-	    if (Start != End)
-	       out << _(" or");
-	    out << endl;
-	    
-	    if (Start == End)
-	       break;
-	    ++Start;
-	 }	 
-      }	    
-   }   
+	 }
+
+	 if (Start != End)
+	    out << _(" or");
+	 out << endl;
+
+	 if (Start == End)
+	    break;
+	 ++Start;
+      }
+   }
+}
+void ShowBroken(ostream &out, CacheFile &Cache, bool const Now)
+{
+   if (Cache->BrokenCount() == 0)
+      return;
+
+   out << _("The following packages have unmet dependencies:") << endl;
+   for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
+   {
+      pkgCache::PkgIterator const I(Cache,Cache.List[J]);
+      ShowBrokenPackage(out, &Cache, I, Now);
+   }
+}
+void ShowBroken(ostream &out, pkgCacheFile &Cache, bool const Now)
+{
+   if (Cache->BrokenCount() == 0)
+      return;
+
+   out << _("The following packages have unmet dependencies:") << endl;
+   for (pkgCache::PkgIterator Pkg = Cache->PkgBegin(); Pkg.end() == false; ++Pkg)
+      ShowBrokenPackage(out, &Cache, Pkg, Now);
 }
 									/*}}}*/
 // ShowNew - Show packages to newly install				/*{{{*/

+ 4 - 3
apt-private/private-output.h

@@ -23,12 +23,13 @@ APT_PUBLIC extern unsigned int ScreenWidth;
 APT_PUBLIC bool InitOutput();
 
 void ListSingleVersion(pkgCacheFile &CacheFile, pkgRecords &records,
-                       pkgCache::VerIterator V, std::ostream &out,
-                       bool include_summary=true);
+                       pkgCache::VerIterator const &V, std::ostream &out,
+                       std::string const &format);
 
 
 // helper to describe global state
-APT_PUBLIC void ShowBroken(std::ostream &out,CacheFile &Cache,bool Now);
+APT_PUBLIC void ShowBroken(std::ostream &out, CacheFile &Cache, bool const Now);
+APT_PUBLIC void ShowBroken(std::ostream &out, pkgCacheFile &Cache, bool const Now);
 
 APT_PUBLIC bool ShowList(std::ostream &out, std::string Title, std::string List,
               std::string VersionsList);

+ 58 - 24
apt-private/private-search.cc

@@ -32,61 +32,95 @@ bool FullTextSearch(CommandLine &CmdL)					/*{{{*/
    pkgCacheFile CacheFile;
    pkgCache *Cache = CacheFile.GetPkgCache();
    pkgDepCache::Policy *Plcy = CacheFile.GetPolicy();
-   pkgRecords records(CacheFile);
    if (unlikely(Cache == NULL || Plcy == NULL))
       return false;
 
-   const char **patterns;
-   patterns = CmdL.FileList + 1;
+   // Make sure there is at least one argument
+   unsigned int const NumPatterns = CmdL.FileSize() -1;
+   if (NumPatterns < 1)
+      return _error->Error(_("You must give at least one search pattern"));
+
+#define APT_FREE_PATTERNS() for (std::vector<regex_t>::iterator P = Patterns.begin(); \
+      P != Patterns.end(); ++P) { regfree(&(*P)); }
+
+   // Compile the regex pattern
+   std::vector<regex_t> Patterns;
+   for (unsigned int I = 0; I != NumPatterns; ++I)
+   {
+      regex_t pattern;
+      if (regcomp(&pattern, CmdL.FileList[I + 1], REG_EXTENDED | REG_ICASE | REG_NOSUB) != 0)
+      {
+	 APT_FREE_PATTERNS();
+	 return _error->Error("Regex compilation error");
+      }
+      Patterns.push_back(pattern);
+   }
+
+   bool const NamesOnly = _config->FindB("APT::Cache::NamesOnly", false);
 
    std::map<std::string, std::string> output_map;
-   std::map<std::string, std::string>::const_iterator K;
 
    LocalitySortedVersionSet bag;
    OpTextProgress progress(*_config);
    progress.OverallProgress(0, 100, 50,  _("Sorting"));
-   GetLocalitySortedVersionSet(CacheFile, bag, progress);
+   GetLocalitySortedVersionSet(CacheFile, &bag, &progress);
    LocalitySortedVersionSet::iterator V = bag.begin();
 
    progress.OverallProgress(50, 100, 50,  _("Full Text Search"));
    progress.SubProgress(bag.size());
+   pkgRecords records(CacheFile);
+
+   std::string format = "${color:highlight}${Package}${color:neutral}/${Origin} ${Version} ${Architecture}${ }${apt:Status}\n";
+   if (_config->FindB("APT::Cache::ShowFull",false) == false)
+      format += "  ${Description}\n";
+   else
+      format += "  ${LongDescription}\n";
+
    int Done = 0;
+   std::vector<bool> PkgsDone(Cache->Head().PackageCount, false);
    for ( ;V != bag.end(); ++V)
    {
       if (Done%500 == 0)
          progress.Progress(Done);
       ++Done;
-      
-      int i;
+
+      // we want to list each package only once
+      pkgCache::PkgIterator const P = V.ParentPkg();
+      if (PkgsDone[P->ID] == true)
+	 continue;
+
+      char const * const PkgName = P.Name();
       pkgCache::DescIterator Desc = V.TranslatedDescription();
       pkgRecords::Parser &parser = records.Lookup(Desc.FileList());
-     
+      std::string const LongDesc = parser.LongDesc();
+
       bool all_found = true;
-      for(i=0; patterns[i] != NULL; ++i)
+      for (std::vector<regex_t>::const_iterator pattern = Patterns.begin();
+	    pattern != Patterns.end(); ++pattern)
       {
-         // FIXME: use regexp instead of simple find()
-         const char *pattern = patterns[i];
-         all_found &=  (
-            strstr(V.ParentPkg().Name(), pattern) != NULL ||
-            strcasestr(parser.ShortDesc().c_str(), pattern) != NULL ||
-            strcasestr(parser.LongDesc().c_str(), pattern) != NULL);
-         // search patterns are AND by default so we can skip looking further
-         // on the first mismatch
-         if(all_found == false)
-            break;
+	 if (regexec(&(*pattern), PkgName, 0, 0, 0) == 0)
+	    continue;
+	 else if (NamesOnly == false && regexec(&(*pattern), LongDesc.c_str(), 0, 0, 0) == 0)
+	    continue;
+	 // search patterns are AND, so one failing fails all
+	 all_found = false;
+	 break;
       }
-      if (all_found)
+      if (all_found == true)
       {
-            std::stringstream outs;
-            ListSingleVersion(CacheFile, records, V, outs);
-            output_map.insert(std::make_pair<std::string, std::string>(
-                                 V.ParentPkg().Name(), outs.str()));
+	 PkgsDone[P->ID] = true;
+	 std::stringstream outs;
+	 ListSingleVersion(CacheFile, records, V, outs, format);
+	 output_map.insert(std::make_pair<std::string, std::string>(
+		  PkgName, outs.str()));
       }
    }
+   APT_FREE_PATTERNS();
    progress.Done();
 
    // FIXME: SORT! and make sorting flexible (alphabetic, by pkg status)
    // output the sorted map
+   std::map<std::string, std::string>::const_iterator K;
    for (K = output_map.begin(); K != output_map.end(); ++K)
       std::cout << (*K).second << std::endl;
 

+ 4 - 4
apt-private/private-show.cc

@@ -141,16 +141,16 @@ bool ShowPackage(CommandLine &CmdL)					/*{{{*/
 {
    pkgCacheFile CacheFile;
    CacheSetHelperVirtuals helper(true, GlobalError::NOTICE);
-   APT::VersionList::Version const select = _config->FindB("APT::Cache::AllVersions", false) ?
-			APT::VersionList::ALL : APT::VersionList::CANDIDATE;
+   APT::CacheSetHelper::VerSelector const select = _config->FindB("APT::Cache::AllVersions", false) ?
+			APT::CacheSetHelper::ALL : APT::CacheSetHelper::CANDIDATE;
    APT::VersionList const verset = APT::VersionList::FromCommandLine(CacheFile, CmdL.FileList + 1, select, helper);
    for (APT::VersionList::const_iterator Ver = verset.begin(); Ver != verset.end(); ++Ver)
       if (DisplayRecord(CacheFile, Ver, c1out) == false)
 	 return false;
 
-   if (select == APT::VersionList::CANDIDATE)
+   if (select == APT::CacheSetHelper::CANDIDATE)
    {
-      APT::VersionList const verset_all = APT::VersionList::FromCommandLine(CacheFile, CmdL.FileList + 1, APT::VersionList::ALL, helper);
+      APT::VersionList const verset_all = APT::VersionList::FromCommandLine(CacheFile, CmdL.FileList + 1, APT::CacheSetHelper::ALL, helper);
       int const records = verset_all.size() - verset.size();
       if (records > 0)
          _error->Notice(P_("There is %i additional record. Please use the '-a' switch to see it", "There are %i additional records. Please use the '-a' switch to see them.", records), records);

+ 29 - 1
apt-private/private-update.cc

@@ -56,10 +56,17 @@ bool DoUpdate(CommandLine &CmdL)
       if (List->GetIndexes(&Fetcher,true) == false)
 	 return false;
 
+      std::string compExt = APT::Configuration::getCompressionTypes()[0];
       pkgAcquire::UriIterator I = Fetcher.UriBegin();
       for (; I != Fetcher.UriEnd(); ++I)
-	 c1out << '\'' << I->URI << "' " << flNotDir(I->Owner->DestFile) << ' ' << 
+      {
+         std::string FileName = flNotDir(I->Owner->DestFile);
+         if(compExt.empty() == false && 
+            APT::String::Endswith(FileName, compExt))
+            FileName = FileName.substr(0, FileName.size() - compExt.size() - 1);
+	 c1out << '\'' << I->URI << "' " << FileName << ' ' << 
             I->Owner->FileSize << ' ' << I->Owner->HashSum() << std::endl;
+      }
       return true;
    }
 
@@ -75,6 +82,27 @@ bool DoUpdate(CommandLine &CmdL)
 	 return false;
    }
 
+   // show basic stats (if the user whishes)
+   if (_config->FindB("APT::Cmd::Show-Update-Stats", false) == true)
+   {
+      int upgradable = 0;
+      Cache.Open();
+      for (pkgCache::PkgIterator I = Cache->PkgBegin(); I.end() != true; ++I)
+      {
+         pkgDepCache::StateCache &state = Cache[I];
+         if (I->CurrentVer != 0 && state.Upgradable() && state.CandidateVer != NULL)
+            upgradable++;
+      }
+      const char *msg = P_(
+         "%i package can be upgraded. Run 'apt list --upgradable' to see it.\n",
+         "%i packages can be upgraded. Run 'apt list --upgradable' to see them.\n",
+         upgradable);
+      if (upgradable == 0)
+         c1out << _("All packages are up to date.") << std::endl;
+      else
+         ioprintf(c1out, msg, upgradable);
+   }
+
    return true;
 }
 									/*}}}*/

+ 3 - 13
apt-private/private-upgrade.cc

@@ -22,19 +22,9 @@ static bool UpgradeHelper(CommandLine &CmdL, int UpgradeFlags)
    if (Cache.OpenForInstall() == false || Cache.CheckDeps() == false)
       return false;
 
-   c0out << _("Calculating upgrade... ") << std::flush;
-   if (APT::Upgrade::Upgrade(Cache, UpgradeFlags) == false)
-   {
-      c0out << _("Failed") << std::endl;
-      ShowBroken(c1out,Cache,false);
-      return _error->Error(_("Internal error, Upgrade broke stuff"));
-   }
-   c0out << _("Done") << std::endl;
-
-   // parse additional cmdline pkg manipulation switches
-   if(!DoCacheManipulationFromCommandLine(CmdL, Cache))
+   if(!DoCacheManipulationFromCommandLine(CmdL, Cache, UpgradeFlags))
       return false;
-   
+
    return InstallPackages(Cache,true);
 }
 
@@ -43,7 +33,7 @@ static bool UpgradeHelper(CommandLine &CmdL, int UpgradeFlags)
 /* Intelligent upgrader that will install and remove packages at will */
 bool DoDistUpgrade(CommandLine &CmdL)
 {
-   return UpgradeHelper(CmdL, 0);
+   return UpgradeHelper(CmdL, APT::Upgrade::ALLOW_EVERYTHING);
 }
 									/*}}}*/
 bool DoUpgrade(CommandLine &CmdL)					/*{{{*/

+ 41 - 17
apt-private/private-utils.cc

@@ -8,45 +8,69 @@
 #include <cstdlib>
 #include <unistd.h>
 
-// DisplayFileInPager - Display File with pager        			/*{{{*/
-void DisplayFileInPager(std::string filename)
+// DisplayFileInPager - Display File with pager				/*{{{*/
+void DisplayFileInPager(std::string const &filename)
 {
-   std::string pager = _config->Find("Dir::Bin::Pager", 
-                                        "/usr/bin/sensible-pager");
-
    pid_t Process = ExecFork();
    if (Process == 0)
    {
       const char *Args[3];
-      Args[0] = pager.c_str();
       Args[1] = filename.c_str();
-      Args[2] = 0;
+      Args[2] = NULL;
+      if (isatty(STDOUT_FILENO) == 1)
+      {
+	 // likely installed, provided by sensible-utils
+	 std::string const pager = _config->Find("Dir::Bin::Pager",
+	       "sensible-pager");
+	 Args[0] = pager.c_str();
+	 execvp(Args[0],(char **)Args);
+	 // lets try some obvious alternatives
+	 Args[0] = getenv("PAGER");
+	 if (Args[0] != NULL)
+	    execvp(Args[0],(char **)Args);
+
+	 Args[0] = "pager";
+	 execvp(Args[0],(char **)Args);
+      }
+      // we could read the file ourselves, but… meh
+      Args[0] = "cat";
       execvp(Args[0],(char **)Args);
       exit(100);
    }
-         
+
    // Wait for the subprocess
-   ExecWait(Process, "sensible-pager", false);
+   ExecWait(Process, "pager", false);
 }
 									/*}}}*/
-// EditFileInSensibleEditor - Edit File with editor    			/*{{{*/
-void EditFileInSensibleEditor(std::string filename)
+// EditFileInSensibleEditor - Edit File with editor			/*{{{*/
+void EditFileInSensibleEditor(std::string const &filename)
 {
-   std::string editor = _config->Find("Dir::Bin::Editor", 
-                                        "/usr/bin/sensible-editor");
-
    pid_t Process = ExecFork();
    if (Process == 0)
    {
+      // likely installed, provided by sensible-utils
+      std::string const editor = _config->Find("Dir::Bin::Editor",
+	    "sensible-editor");
       const char *Args[3];
       Args[0] = editor.c_str();
       Args[1] = filename.c_str();
-      Args[2] = 0;
+      Args[2] = NULL;
+      execvp(Args[0],(char **)Args);
+      // the usual suspects we can try as an alternative
+      Args[0] = getenv("VISUAL");
+      if (Args[0] != NULL)
+	 execvp(Args[0],(char **)Args);
+
+      Args[0] = getenv("EDITOR");
+      if (Args[0] != NULL)
+	 execvp(Args[0],(char **)Args);
+
+      Args[0] = "editor";
       execvp(Args[0],(char **)Args);
       exit(100);
    }
-         
+
    // Wait for the subprocess
-   ExecWait(Process, "sensible-editor", false);
+   ExecWait(Process, "editor", false);
 }
 									/*}}}*/

+ 2 - 2
apt-private/private-utils.h

@@ -5,7 +5,7 @@
 
 #include <string>
 
-APT_PUBLIC void DisplayFileInPager(std::string filename);
-APT_PUBLIC void EditFileInSensibleEditor(std::string filename);
+APT_PUBLIC void DisplayFileInPager(std::string const &filename);
+APT_PUBLIC void EditFileInSensibleEditor(std::string const &filename);
 
 #endif

+ 4 - 0
buildlib/config.h.in

@@ -28,6 +28,10 @@
 /* If there is no socklen_t, define this for the netdb shim */
 #undef NEED_SOCKLEN_T_DEFINE
 
+/* We need the getresuid() function */
+#undef HAVE_GETRESUID
+#undef HAVE_GETRESGID
+
 /* Define to the size of the filesize containing structures */
 #undef _FILE_OFFSET_BITS
 

+ 0 - 60
buildlib/debiandoc.mak

@@ -1,60 +0,0 @@
-# -*- make -*-
-
-# This processes debian-doc sgml to produce html and plain text output
-
-# Input
-# $(SOURCE) - The documents to use
-
-# All output is writtin to files in the build doc directory
-
-# See defaults.mak for information about LOCAL
-
-# Some local definitions
-LOCAL := debiandoc-$(firstword $(SOURCE))
-$(LOCAL)-HTML := $(addsuffix .html,$(addprefix $(DOC)/,$(basename $(SOURCE))))
-$(LOCAL)-TEXT := $(addsuffix .text,$(addprefix $(DOC)/,$(basename $(SOURCE))))
-
-debiandoc:
-
-#---------
-
-# Rules to build HTML documentations
-ifdef DEBIANDOC_HTML
-
-# Install generation hooks
-debiandoc: $($(LOCAL)-HTML)
-veryclean: veryclean/html/$(LOCAL)
-
-vpath %.sgml $(SUBDIRS)
-$(DOC)/%.html: %.sgml
-	echo Creating html for $< to $@
-	-rm -rf $@
-	(HERE=`pwd`; cd $(@D) && $(DEBIANDOC_HTML) $(DEBIANDOC_HTML_OPTIONS) $$HERE/$<) || exit 199
-
-# Clean rule
-.PHONY: veryclean/html/$(LOCAL)
-veryclean/html/$(LOCAL):
-	-rm -rf $($(@F)-HTML)
-	
-endif
-
-#---------
-
-# Rules to build Text documentations
-ifdef DEBIANDOC_TEXT
-
-# Install generation hooks
-debiandoc: $($(LOCAL)-TEXT)
-veryclean: veryclean/text/$(LOCAL)
-
-vpath %.sgml $(SUBDIRS)
-$(DOC)/%.text: %.sgml
-	echo Creating text for $< to $@
-	$(DEBIANDOC_TEXT) -O $< > $@ || exit 198
-
-# Clean rule
-.PHONY: veryclean/text/$(LOCAL)
-veryclean/text/$(LOCAL):
-	-rm -rf $($(@F)-TEXT)
-	
-endif

+ 0 - 0
buildlib/defaults.mak


Vissa filer visades inte eftersom för många filer har ändrats