Quellcode durchsuchen

merged from lp:~donkult/apt/sid

Michael Vogt vor 16 Jahren
Ursprung
Commit
46361a17f0
79 geänderte Dateien mit 15642 neuen und 2907 gelöschten Zeilen
  1. 12 9
      .bzrignore
  2. 113 0
      README.MultiArch
  3. 53 9
      apt-pkg/algorithms.cc
  4. 26 1
      apt-pkg/aptconfiguration.cc
  5. 16 0
      apt-pkg/aptconfiguration.h
  6. 345 378
      apt-pkg/cacheiterators.h
  7. 15 22
      apt-pkg/cdrom.cc
  8. 3 3
      apt-pkg/clean.cc
  9. 41 1
      apt-pkg/contrib/cmndline.cc
  10. 1 0
      apt-pkg/contrib/cmndline.h
  11. 4 4
      apt-pkg/contrib/error.h
  12. 18 16
      apt-pkg/contrib/macros.h
  13. 59 11
      apt-pkg/contrib/mmap.cc
  14. 5 0
      apt-pkg/contrib/mmap.h
  15. 44 32
      apt-pkg/contrib/strutl.cc
  16. 8 16
      apt-pkg/contrib/strutl.h
  17. 11 4
      apt-pkg/deb/debindexfile.cc
  18. 3 1
      apt-pkg/deb/debindexfile.h
  19. 175 44
      apt-pkg/deb/deblistparser.cc
  20. 3 1
      apt-pkg/deb/deblistparser.h
  21. 186 112
      apt-pkg/deb/debmetaindex.cc
  22. 16 12
      apt-pkg/deb/debmetaindex.h
  23. 16 2
      apt-pkg/deb/debversion.cc
  24. 11 7
      apt-pkg/deb/dpkgpm.cc
  25. 330 69
      apt-pkg/depcache.cc
  26. 13 7
      apt-pkg/depcache.h
  27. 2 2
      apt-pkg/metaindex.h
  28. 9 4
      apt-pkg/orderlist.cc
  29. 24 8
      apt-pkg/packagemanager.cc
  30. 199 41
      apt-pkg/pkgcache.cc
  31. 40 14
      apt-pkg/pkgcache.h
  32. 238 74
      apt-pkg/pkgcachegen.cc
  33. 12 5
      apt-pkg/pkgcachegen.h
  34. 22 19
      apt-pkg/policy.cc
  35. 45 36
      apt-pkg/sourcelist.cc
  36. 5 3
      apt-pkg/sourcelist.h
  37. 2 11
      apt-pkg/tagfile.cc
  38. 14 1
      apt-pkg/tagfile.h
  39. 7 1
      apt-pkg/versionmatch.cc
  40. 2 0
      apt-pkg/versionmatch.h
  41. 57 42
      cmdline/apt-cache.cc
  42. 86 50
      cmdline/apt-get.cc
  43. 4 0
      cmdline/apt-mark
  44. 2 1
      debian/apt-doc.docs
  45. 62 0
      debian/changelog
  46. 3 4
      debian/control
  47. 1 0
      debian/source/format
  48. 30 5
      doc/apt-ftparchive.1.xml
  49. 7 0
      doc/apt-get.8.xml
  50. 7 2
      doc/apt.ent
  51. 13 7
      doc/apt_preferences.5.xml
  52. 0 11
      doc/es/makefile
  53. 2 0
      doc/examples/configure-index
  54. 0 11
      doc/fr/makefile
  55. 0 11
      doc/it/makefile
  56. 0 11
      doc/ja/makefile
  57. 2 2
      doc/de/makefile
  58. 11 5
      doc/makefile
  59. 0 11
      doc/pl/makefile
  60. 184 155
      doc/po/apt-doc.pot
  61. 218 205
      doc/po/de.po
  62. 199 162
      doc/po/es.po
  63. 192 156
      doc/po/fr.po
  64. 182 158
      doc/po/it.po
  65. 195 159
      doc/po/ja.po
  66. 196 164
      doc/po/pl.po
  67. 11096 0
      doc/po/pt.po
  68. 184 161
      doc/po/pt_BR.po
  69. 0 11
      doc/pt_BR/makefile
  70. 52 11
      ftparchive/apt-ftparchive.cc
  71. 53 2
      ftparchive/writer.cc
  72. 21 0
      ftparchive/writer.h
  73. 201 166
      po/apt-all.pot
  74. 39 0
      test/libapt/commandlineasstring_test.cc
  75. 123 0
      test/libapt/compareversion_test.cc
  76. 12 0
      test/libapt/makefile
  77. 0 7
      test/makefile
  78. 60 4
      test/versions.lst
  79. 0 233
      test/versiontest.cc

+ 12 - 9
.bzrignore

@@ -11,14 +11,17 @@ configure
 buildlib/config.sub
 buildlib/config.guess
 
+# abichecker related files/dir
+abicheck/apt_build.xml
+abicheck/apt_installed.xml
+abicheck/compat_reports/
+abicheck/descriptors_storage/
+abicheck/header_compile_errors/
+abicheck/test_results/
+abicheck/tests/
+
 # generated files in the progress to build all
 # apt man pages and other documentation
-doc/*.1
-doc/*.5
-doc/*.8
-doc/*/*.1
-doc/*/*.5
-doc/*/*.8
-doc/*/apt.ent
-doc/*/*.xml
-doc/*/*.sgml
+./doc/*/
+!./doc/examples/
+!./doc/po/

+ 113 - 0
README.MultiArch

@@ -0,0 +1,113 @@
+Before we start with this topic: Note that MultiArch is not yet ready for
+prime time and/or for the casual user. The implementation is so far widely
+untested and only useful for developers of packagemanagment tools which
+use APT and his friends and maintainers of (upcoming) MultiArch packages.
+This README is especially NOT written for the casual user and is NOT a
+usage guide - you have been warned. It is assumed that the reader has
+at least a bit of knowledge about APT internals, dependency relations
+and the MultiArch spec [0].
+
+Note also that the toolchain isn't ready yet, e.g. while you can simulate
+the installation of MultiArch packages they will more sooner than later
+cause enormous problems if really installed as dpkg can't handle MultiArch
+yet (no, --force-{overwrite,architecture} aren't good options here).
+Other parts of the big picture are missing and/or untested too.
+You have been warned!
+
+
+The implementation is focused on NOT breaking existing singleArch-only
+applications and/or systems as this is the current status-quo for all
+systems. Also, many systems don't need (or can't make use of) MultiArch,
+so APT will proceed in thinking SingleArch as long as it is not explicitly
+told to handle MultiArch:
+To activate MultiArch handling you need to specify architectures you
+want to be considered by APT with the config list APT::Architectures
+(Insert architectures in order of preference).
+APT will download Packages files for all these architectures in the
+update step. Exception: In the sourcelist is the optionfield used:
+deb [ arch=amd64,i386 ] http://example.org/ experimental main
+(This optionfield is a NOP in previous apt versions)
+
+Internally in APT a package is represented as a PkgIterator -
+before MultiArch this PkgIterator was architecture unaware,
+only VerIterators include the architecture they came from.
+This is/was a big problem as all versions in a package are
+considered for dependency resolution, so pinning will not work in all cases.
+
+The problem is solved by a conceptional change:
+A PkgIterator is now architecture aware, so the packages
+of foobar for amd64 and for i386 are now for apt internal totally
+different packages. That is a good thing for e.g. pinning, but
+sometimes you need the information that such packages are belonging together:
+All these foobar packages therefore form a Group accessible with GrpIterators.
+Note that the GrpIterator has the same name as all the packages in this group,
+so e.g. apt-cache pkgnames iterates over GrpIterator to get the package names:
+This is compatible to SingleArch as a Group consists only of a single package
+and also to MultiArch as a Group consists of possible many packages which
+all have the same name and are therefore out of interest for pkgnames.
+
+
+Caused by the paragraph "Dependencies involving Architecture: all packages"
+in the MultiArch spec we have a second major conceptional change
+which could even break existing applications, but we hope for the best…
+An Architecture: all package is internally split into pseudo packages
+for all MultiArch Architectures and additional a package with the
+architecture "all" with no dependencies which is a dependency of all
+these architecture depending packages. While the architecture depending
+packages are mainly used for dependency resolution (a package of arch A which
+depends on an arch all package assumes that the dependencies of this package
+are also from arch A. Packages also sometimes change from any to all or v.v.)
+the arch "all" package is used for scheduling download/installation of the
+underlying "real" package. Note that the architecture depending packages can
+be detected with Pseudo() while the "all" package reports exactly this arch
+as package architecture and as pseudo architecture of the versions of this pkg.
+Beware: All versions of a "real" architecture all package will be report "all"
+as their architecture if asked with Arch() regardless if they are the "all" or
+the architecture depending packages. If you want to know the architecture this
+pseudo package was created for call Arch(true). Also, while the spec say that
+arch:all packages are not allowed to have a MultiArch flag APT assigns a
+special value to them: MultiArch: all.
+
+
+As you might guess this arch:all handling has a few problems (but we think so
+far that the problems are minor compared to the problems we would have with
+other implementations.)
+APT doesn't know which pseudo packages of such an arch all package are
+"installed" (to satisfy dependencies), so APT will generate a Cache in which
+all these pseudo packages are installed (e.g. apt-cache policy will display
+them all as installed). Later in the DepCache step it will "remove"
+all pseudo packages whose dependencies are not satisfied.
+The expense is that if the package state is broken APT could come to the
+conclusion to "remove" too many pseudo packages, but in a stable environment
+APT should never end up in a broken system state…
+
+
+Given all these internal changes it is quite interesting that the actual
+implementation of MultiArch is trivial: Some implicit dependencies and a few
+more provides are all changes needed to get it working. Especially noteworthy
+is that it wasn't needed to change the resolver in any way and other parts only
+need to be told about ignoring pseudo packages or using GrpIterator instead of
+PkgIterator, so chances are good that libapt-applications will proceed to work
+without or at least only require minor changes, but your mileage may vary…
+
+
+Known Issues and/or noteworthy stuff:
+* The implementation is mostly untested, so it is very likely that APT will
+  eat your kids if you aren't as lucky as the author of these patches.
+* the (install)size of a pseudo package is always NULL - if you want to know
+  the (install)size you need to get the info from the arch "all" package.
+* It is maybe confusing, but the arch "all" package does have the same versions
+  and in general roughly the same information with one subtil difference:
+  It doesn't have any dependency, regardless of the type. The pseudo packages
+  depend on this package.
+* apt-cache policy foobar on installed architecture all package foobar will
+  report all architecture depending packages as installed. Displaying here the
+  correct information would require to build the complete DepCache…
+* [BUG] An installed package which changes the architecture from any to all
+  (and v.v.) shows up in the NEW packages section instead of UPGRADE.
+* [TODO] Investigate the DepCache pseudo-package killer heuristic:
+  e.g. add more safety guards…
+* [FIXME] a few corner cases/missing features marked as FIXME in the code
+
+
+[0] https://wiki.ubuntu.com/MultiarchSpec

+ 53 - 9
apt-pkg/algorithms.cc

@@ -83,13 +83,28 @@ void pkgSimulate::Describe(PkgIterator Pkg,ostream &out,bool Current,bool Candid
 bool pkgSimulate::Install(PkgIterator iPkg,string /*File*/)
 {
    // Adapt the iterator
-   PkgIterator Pkg = Sim.FindPkg(iPkg.Name());
+   PkgIterator Pkg = Sim.FindPkg(iPkg.Name(), iPkg.Arch());
    Flags[Pkg->ID] = 1;
    
    cout << "Inst ";
    Describe(Pkg,cout,true,true);
    Sim.MarkInstall(Pkg,false);
-   
+
+   if (strcmp(Pkg.Arch(),"all") == 0)
+   {
+      pkgCache::GrpIterator G = Pkg.Group();
+      pkgCache::GrpIterator iG = iPkg.Group();
+      for (pkgCache::PkgIterator P = G.FindPkg("any"); P.end() != true; P = G.NextPkg(P))
+      {
+	 if (strcmp(P.Arch(), "all") == 0)
+	    continue;
+	 if (iG.FindPkg(P.Arch())->CurrentVer == 0)
+	    continue;
+	 Flags[P->ID] = 1;
+	 Sim.MarkInstall(P, false);
+      }
+   }
+
    // Look for broken conflicts+predepends.
    for (PkgIterator I = Sim.PkgBegin(); I.end() == false; I++)
    {
@@ -131,9 +146,22 @@ bool pkgSimulate::Install(PkgIterator iPkg,string /*File*/)
 bool pkgSimulate::Configure(PkgIterator iPkg)
 {
    // Adapt the iterator
-   PkgIterator Pkg = Sim.FindPkg(iPkg.Name());
+   PkgIterator Pkg = Sim.FindPkg(iPkg.Name(), iPkg.Arch());
    
    Flags[Pkg->ID] = 2;
+
+   if (strcmp(Pkg.Arch(),"all") == 0)
+   {
+      pkgCache::GrpIterator G = Pkg.Group();
+      for (pkgCache::PkgIterator P = G.FindPkg("any"); P.end() != true; P = G.NextPkg(P))
+      {
+	 if (strcmp(P.Arch(), "all") == 0)
+	    continue;
+	 if (Flags[P->ID] == 1)
+	    Flags[P->ID] = 2;
+      }
+   }
+
 //   Sim.MarkInstall(Pkg,false);
    if (Sim[Pkg].InstBroken() == true)
    {
@@ -181,10 +209,26 @@ bool pkgSimulate::Configure(PkgIterator iPkg)
 bool pkgSimulate::Remove(PkgIterator iPkg,bool Purge)
 {
    // Adapt the iterator
-   PkgIterator Pkg = Sim.FindPkg(iPkg.Name());
+   PkgIterator Pkg = Sim.FindPkg(iPkg.Name(), iPkg.Arch());
 
    Flags[Pkg->ID] = 3;
    Sim.MarkDelete(Pkg);
+
+   if (strcmp(Pkg.Arch(),"all") == 0)
+   {
+      pkgCache::GrpIterator G = Pkg.Group();
+      pkgCache::GrpIterator iG = iPkg.Group();
+      for (pkgCache::PkgIterator P = G.FindPkg("any"); P.end() != true; P = G.NextPkg(P))
+      {
+	 if (strcmp(P.Arch(), "all") == 0)
+	    continue;
+	 if (iG.FindPkg(P.Arch())->CurrentVer == 0)
+	    continue;
+	 Flags[P->ID] = 3;
+	 Sim.MarkDelete(P);
+      }
+   }
+
    if (Purge == true)
       cout << "Purg ";
    else
@@ -491,11 +535,11 @@ void pkgProblemResolver::MakeScores()
    // Important Required Standard Optional Extra
    signed short PrioMap[] = {
       0,
-      _config->FindI("pkgProblemResolver::Scores::Important",3),
-      _config->FindI("pkgProblemResolver::Scores::Required",2),
-      _config->FindI("pkgProblemResolver::Scores::Standard",1),
-      _config->FindI("pkgProblemResolver::Scores::Optional",-1),
-      _config->FindI("pkgProblemResolver::Scores::Extra",-2)
+      (signed short) _config->FindI("pkgProblemResolver::Scores::Important",3),
+      (signed short) _config->FindI("pkgProblemResolver::Scores::Required",2),
+      (signed short) _config->FindI("pkgProblemResolver::Scores::Standard",1),
+      (signed short) _config->FindI("pkgProblemResolver::Scores::Optional",-1),
+      (signed short) _config->FindI("pkgProblemResolver::Scores::Extra",-2)
    };
    signed short PrioEssentials = _config->FindI("pkgProblemResolver::Scores::Essentials",100);
    signed short PrioInstalledAndNotObsolete = _config->FindI("pkgProblemResolver::Scores::NotObsolete",1);

+ 26 - 1
apt-pkg/aptconfiguration.cc

@@ -152,6 +152,7 @@ std::vector<std::string> const Configuration::getLanguages(bool const &All,
 			builtin.push_back(c);
 		}
 	}
+	closedir(D);
 
 	// get the environment language codes: LC_MESSAGES (and later LANGUAGE)
 	// we extract both, a long and a short code and then we will
@@ -220,7 +221,7 @@ std::vector<std::string> const Configuration::getLanguages(bool const &All,
 	const char *language_env = getenv("LANGUAGE") == 0 ? "" : getenv("LANGUAGE");
 	string envLang = Locale == 0 ? language_env : *(Locale+1);
 	if (envLang.empty() == false) {
-		std::vector<string> env = ExplodeString(envLang,':');
+		std::vector<string> env = VectorizeString(envLang,':');
 		short addedLangs = 0; // add a maximum of 3 fallbacks from the environment
 		for (std::vector<string>::const_iterator e = env.begin();
 		     e != env.end() && addedLangs < 3; ++e) {
@@ -318,4 +319,28 @@ std::vector<std::string> const Configuration::getLanguages(bool const &All,
 		return codes;
 }
 									/*}}}*/
+// getArchitectures - Return Vector of prefered Architectures		/*{{{*/
+std::vector<std::string> const Configuration::getArchitectures(bool const &Cached) {
+	using std::string;
+
+	std::vector<string> static archs;
+	if (likely(Cached == true) && archs.empty() == false)
+		return archs;
+
+	string const arch = _config->Find("APT::Architecture");
+	archs = _config->FindVector("APT::Architectures");
+	if (archs.empty() == true ||
+	    std::find(archs.begin(), archs.end(), arch) == archs.end())
+		archs.push_back(arch);
+	return archs;
+}
+									/*}}}*/
+// checkArchitecture - are we interested in the given Architecture?	/*{{{*/
+bool const Configuration::checkArchitecture(std::string const &Arch) {
+	if (Arch == "all")
+		return true;
+	std::vector<std::string> const archs = getArchitectures(true);
+	return (std::find(archs.begin(), archs.end(), Arch) != archs.end());
+}
+									/*}}}*/
 }

+ 16 - 0
apt-pkg/aptconfiguration.h

@@ -66,6 +66,22 @@ public:									/*{{{*/
 	std::vector<std::string> static const getLanguages(bool const &All = false,
 			bool const &Cached = true, char const ** const Locale = 0);
 
+	/** \brief Returns a vector of Architectures we support
+	 *
+	 *  \param Cached saves the result so we need to calculated it only once
+	 *                this parameter should ony be used for testing purposes.
+	 *
+	 *  \return a vector of Architectures in prefered order
+	 */
+	std::vector<std::string> static const getArchitectures(bool const &Cached = true);
+
+	/** \brief Are we interested in the given Architecture?
+	 *
+	 *  \param Arch we want to check
+	 *  \return true if we are interested, false otherwise
+	 */
+	bool static const checkArchitecture(std::string const &Arch);
+
 									/*}}}*/
 };
 									/*}}}*/

+ 345 - 378
apt-pkg/cacheiterators.h

@@ -1,6 +1,5 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: cacheiterators.h,v 1.18.2.1 2004/05/08 22:44:27 mdz Exp $
 /* ######################################################################
    
    Cache Iterators - Iterators for navigating the cache structure
@@ -30,417 +29,385 @@
 									/*}}}*/
 #ifndef PKGLIB_CACHEITERATORS_H
 #define PKGLIB_CACHEITERATORS_H
+// abstract Iterator template						/*{{{*/
+/* This template provides the very basic iterator methods we
+   need to have for doing some walk-over-the-cache magic */
+template<typename Str, typename Itr> class pkgCache::Iterator {
+	protected:
+	Str *S;
+	pkgCache *Owner;
+
+	/** \brief Returns the Pointer for this struct in the owner
+	 *  The implementation of this method should be pretty short
+	 *  as it will only return the Pointer into the mmap stored
+	 *  in the owner but the name of this pointer is different for
+	 *  each stucture and we want to abstract here at least for the
+	 *  basic methods from the actual structure.
+	 *  \return Pointer to the first structure of this type
+	 */
+	virtual Str* OwnerPointer() const = 0;
+
+	public:
+	// Iteration
+	virtual void operator ++(int) = 0;
+	virtual void operator ++() = 0; // Should be {operator ++(0);};
+	inline bool end() const {return Owner == 0 || S == OwnerPointer();};
+
+	// Comparison
+	inline bool operator ==(const Itr &B) const {return S == B.S;};
+	inline bool operator !=(const Itr &B) const {return S != B.S;};
+
+	// Accessors
+	inline Str *operator ->() {return S;};
+	inline Str const *operator ->() const {return S;};
+	inline operator Str *() {return S == OwnerPointer() ? 0 : S;};
+	inline operator Str const *() const {return S == OwnerPointer() ? 0 : S;};
+	inline Str &operator *() {return *S;};
+	inline Str const &operator *() const {return *S;};
+	inline pkgCache *Cache() {return Owner;};
+
+	// Mixed stuff
+	inline void operator =(const Itr &B) {S = B.S; Owner = B.Owner;};
+	inline bool IsGood() const { return S && Owner && ! end();};
+	inline unsigned long Index() const {return S - OwnerPointer();};
+
+	// Constructors - look out for the variable assigning
+	inline Iterator() : S(0), Owner(0) {};
+	inline Iterator(pkgCache &Owner,Str *T = 0) : S(T), Owner(&Owner) {};
+};
+									/*}}}*/
+// Group Iterator							/*{{{*/
+/* Packages with the same name are collected in a Group so someone only
+   interest in package names can iterate easily over the names, so the
+   different architectures can be treated as of the "same" package
+   (apt internally treat them as totally different packages) */
+class pkgCache::GrpIterator: public Iterator<Group, GrpIterator> {
+	long HashIndex;
+
+	protected:
+	inline Group* OwnerPointer() const {
+		return Owner->GrpP;
+	};
+
+	public:
+	// This constructor is the 'begin' constructor, never use it.
+	inline GrpIterator(pkgCache &Owner) : Iterator<Group, GrpIterator>(Owner), HashIndex(-1) {
+		S = OwnerPointer();
+		operator ++(0);
+	};
+
+	virtual void operator ++(int);
+	virtual void operator ++() {operator ++(0);};
+
+	inline const char *Name() const {return S->Name == 0?0:Owner->StrP + S->Name;};
+	inline PkgIterator PackageList() const;
+	PkgIterator FindPkg(string Arch = "any");
+	PkgIterator NextPkg(PkgIterator const &Pkg);
+
+	// Constructors
+	inline GrpIterator(pkgCache &Owner, Group *Trg) : Iterator<Group, GrpIterator>(Owner, Trg), HashIndex(0) {
+		if (S == 0)
+			S = OwnerPointer();
+	};
+	inline GrpIterator() : Iterator<Group, GrpIterator>(), HashIndex(0) {};
 
-
+};
+									/*}}}*/
 // Package Iterator							/*{{{*/
-class pkgCache::PkgIterator
-{
-   friend class pkgCache;
-   Package *Pkg;
-   pkgCache *Owner;
-   long HashIndex;
-
-   protected:
-   
-   // This constructor is the 'begin' constructor, never use it.
-   inline PkgIterator(pkgCache &Owner) : Owner(&Owner), HashIndex(-1)
-   {
-      Pkg = Owner.PkgP;
-      operator ++(0);
-   };
-   
-   public:
-
-   enum OkState {NeedsNothing,NeedsUnpack,NeedsConfigure};
-      
-   // Iteration
-   void operator ++(int);
-   inline void operator ++() {operator ++(0);};
-   inline bool end() const {return Owner == 0 || Pkg == Owner->PkgP?true:false;};
-
-   // Comparison
-   inline bool operator ==(const PkgIterator &B) const {return Pkg == B.Pkg;};
-   inline bool operator !=(const PkgIterator &B) const {return Pkg != B.Pkg;};
-			   
-   // Accessors
-   inline Package *operator ->() {return Pkg;};
-   inline Package const *operator ->() const {return Pkg;};
-   inline Package const &operator *() const {return *Pkg;};
-   inline operator Package *() {return Pkg == Owner->PkgP?0:Pkg;};
-   inline operator Package const *() const {return Pkg == Owner->PkgP?0:Pkg;};
-   inline pkgCache *Cache() {return Owner;};
-   
-   inline const char *Name() const {return Pkg->Name == 0?0:Owner->StrP + Pkg->Name;};
-   inline const char *Section() const {return Pkg->Section == 0?0:Owner->StrP + Pkg->Section;};
-   inline bool Purge() const {return Pkg->CurrentState == pkgCache::State::Purge ||
-	 (Pkg->CurrentVer == 0 && Pkg->CurrentState == pkgCache::State::NotInstalled);};
-   inline VerIterator VersionList() const;
-   inline VerIterator CurrentVer() const;
-   inline DepIterator RevDependsList() const;
-   inline PrvIterator ProvidesList() const;
-   inline unsigned long Index() const {return Pkg - Owner->PkgP;};
-   OkState State() const;
-
-   //Nice printable representation
-   friend std::ostream& operator<<(std::ostream& out, pkgCache::PkgIterator Pkg);
-
-   const char *CandVersion() const;
-   const char *CurVersion() const;
-
-   // Constructors
-   inline PkgIterator(pkgCache &Owner,Package *Trg) : Pkg(Trg), Owner(&Owner),
-          HashIndex(0) 
-   { 
-      if (Pkg == 0)
-	 Pkg = Owner.PkgP;
-   };
-   inline PkgIterator() : Pkg(0), Owner(0), HashIndex(0) {};
+class pkgCache::PkgIterator: public Iterator<Package, PkgIterator> {
+	long HashIndex;
+
+	protected:
+	inline Package* OwnerPointer() const {
+		return Owner->PkgP;
+	};
+
+	public:
+	// This constructor is the 'begin' constructor, never use it.
+	inline PkgIterator(pkgCache &Owner) : Iterator<Package, PkgIterator>(Owner), HashIndex(-1) {
+		S = OwnerPointer();
+		operator ++(0);
+	};
+
+	virtual void operator ++(int);
+	virtual void operator ++() {operator ++(0);};
+
+	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 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;};
+	inline GrpIterator Group() const { return GrpIterator(*Owner, Owner->GrpP + S->Group);};
+
+	inline VerIterator VersionList() const;
+	inline VerIterator CurrentVer() const;
+	inline DepIterator RevDependsList() const;
+	inline PrvIterator ProvidesList() const;
+	OkState State() const;
+	const char *CandVersion() const;
+	const char *CurVersion() const;
+
+	//Nice printable representation
+	friend std::ostream& operator <<(std::ostream& out, PkgIterator i);
+	std::string FullName(bool const &Pretty = false) const;
+
+	// Constructors
+	inline PkgIterator(pkgCache &Owner,Package *Trg) : Iterator<Package, PkgIterator>(Owner, Trg), HashIndex(0) {
+		if (S == 0)
+			S = OwnerPointer();
+	};
+	inline PkgIterator() : Iterator<Package, PkgIterator>(), HashIndex(0) {};
 };
 									/*}}}*/
 // Version Iterator							/*{{{*/
-class pkgCache::VerIterator
-{
-   Version *Ver;
-   pkgCache *Owner;
-
-   void _dummy();
-   
-   public:
-
-   // Iteration
-   void operator ++(int) {if (Ver != Owner->VerP) Ver = Owner->VerP + Ver->NextVer;};
-   inline void operator ++() {operator ++(0);};
-   inline bool end() const {return Owner == 0 || (Ver == Owner->VerP?true:false);};
-   inline void operator =(const VerIterator &B) {Ver = B.Ver; Owner = B.Owner;};
-   
-   // Comparison
-   inline bool operator ==(const VerIterator &B) const {return Ver == B.Ver;};
-   inline bool operator !=(const VerIterator &B) const {return Ver != B.Ver;};
-   int CompareVer(const VerIterator &B) const;
-
-   // Testing
-   inline bool IsGood() const { return Ver && Owner && ! end();};
-
-   // Accessors
-   inline Version *operator ->() {return Ver;};
-   inline Version const *operator ->() const {return Ver;};
-   inline Version &operator *() {return *Ver;};
-   inline Version const &operator *() const {return *Ver;};
-   inline operator Version *() {return Ver == Owner->VerP?0:Ver;};
-   inline operator Version const *() const {return Ver == Owner->VerP?0:Ver;};
-   inline pkgCache *Cache() {return Owner;};
-      
-   inline const char *VerStr() const {return Ver->VerStr == 0?0:Owner->StrP + Ver->VerStr;};
-   inline const char *Section() const {return Ver->Section == 0?0:Owner->StrP + Ver->Section;};
-   inline const char *Arch() const {return Ver->Arch == 0?0:Owner->StrP + Ver->Arch;};
-   inline PkgIterator ParentPkg() const {return PkgIterator(*Owner,Owner->PkgP + Ver->ParentPkg);};
-   inline DescIterator DescriptionList() const;
-   DescIterator TranslatedDescription() const;
-   inline DepIterator DependsList() const;
-   inline PrvIterator ProvidesList() const;
-   inline VerFileIterator FileList() const;
-   inline unsigned long Index() const {return Ver - Owner->VerP;};
-   bool Downloadable() const;
-   inline const char *PriorityType() {return Owner->Priority(Ver->Priority);};
-   string RelStr();
-   
-   bool Automatic() const;
-   VerFileIterator NewestFile() const;
-
-   inline VerIterator() : Ver(0), Owner(0) {};   
-   inline VerIterator(pkgCache &Owner,Version *Trg = 0) : Ver(Trg), 
-              Owner(&Owner) 
-   { 
-      if (Ver == 0)
-	 Ver = Owner.VerP;
-   };
+class pkgCache::VerIterator : public Iterator<Version, VerIterator> {
+	protected:
+	inline Version* OwnerPointer() const {
+		return Owner->VerP;
+	};
+
+	public:
+	// Iteration
+	void operator ++(int) {if (S != Owner->VerP) S = Owner->VerP + S->NextVer;};
+	inline void operator ++() {operator ++(0);};
+
+	// Comparison
+	int CompareVer(const VerIterator &B) const;
+
+	// 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;};
+	inline const char *Arch() const {
+		if(S->MultiArch == pkgCache::Version::All)
+			return "all";
+		return S->ParentPkg == 0?0:Owner->StrP + ParentPkg()->Arch;
+	};
+	inline const char *Arch(bool const pseudo) const {
+		if(pseudo == false)
+			return Arch();
+		return S->ParentPkg == 0?0:Owner->StrP + ParentPkg()->Arch;
+	};
+	inline PkgIterator ParentPkg() const {return PkgIterator(*Owner,Owner->PkgP + S->ParentPkg);};
+
+	inline DescIterator DescriptionList() const;
+	DescIterator TranslatedDescription() const;
+	inline DepIterator DependsList() const;
+	inline PrvIterator ProvidesList() const;
+	inline VerFileIterator FileList() const;
+	bool Downloadable() const;
+	inline const char *PriorityType() {return Owner->Priority(S->Priority);};
+	string RelStr();
+
+	bool Automatic() const;
+	bool Pseudo() const;
+	VerFileIterator NewestFile() const;
+
+	inline VerIterator(pkgCache &Owner,Version *Trg = 0) : Iterator<Version, VerIterator>(Owner, Trg) {
+		if (S == 0)
+			S = OwnerPointer();
+	};
+	inline VerIterator() : Iterator<Version, VerIterator>() {};
 };
 									/*}}}*/
 // Description Iterator							/*{{{*/
-class pkgCache::DescIterator
-{
-   Description *Desc;
-   pkgCache *Owner;
-   
-   void _dummy();
-   
-   public:
-
-   // Iteration
-   void operator ++(int) {if (Desc != Owner->DescP) Desc = Owner->DescP + Desc->NextDesc;};
-   inline void operator ++() {operator ++(0);};
-   inline bool end() const {return Owner == 0 || Desc == Owner->DescP?true:false;};
-   inline void operator =(const DescIterator &B) {Desc = B.Desc; Owner = B.Owner;};
-   
-   // Comparison
-   inline bool operator ==(const DescIterator &B) const {return Desc == B.Desc;};
-   inline bool operator !=(const DescIterator &B) const {return Desc != B.Desc;};
-   int CompareDesc(const DescIterator &B) const;
-   
-   // Accessors
-   inline Description *operator ->() {return Desc;};
-   inline Description const *operator ->() const {return Desc;};
-   inline Description &operator *() {return *Desc;};
-   inline Description const &operator *() const {return *Desc;};
-   inline operator Description *() {return Desc == Owner->DescP?0:Desc;};
-   inline operator Description const *() const {return Desc == Owner->DescP?0:Desc;};
-   inline pkgCache *Cache() {return Owner;};
-      
-   inline const char *LanguageCode() const {return Owner->StrP + Desc->language_code;};
-   inline const char *md5() const {return Owner->StrP + Desc->md5sum;};
-   inline DescFileIterator FileList() const;
-   inline unsigned long Index() const {return Desc - Owner->DescP;};
-
-   inline DescIterator() : Desc(0), Owner(0) {};   
-   inline DescIterator(pkgCache &Owner,Description *Trg = 0) : Desc(Trg), 
-              Owner(&Owner) 
-   { 
-      if (Desc == 0)
-	 Desc = Owner.DescP;
-   };
+class pkgCache::DescIterator : public Iterator<Description, DescIterator> {
+	protected:
+	inline Description* OwnerPointer() const {
+		return Owner->DescP;
+	};
+
+	public:
+	// Iteration
+	void operator ++(int) {if (S != Owner->DescP) S = Owner->DescP + S->NextDesc;};
+	inline void operator ++() {operator ++(0);};
+
+	// Comparison
+	int CompareDesc(const DescIterator &B) const;
+
+	// Accessors
+	inline const char *LanguageCode() const {return Owner->StrP + S->language_code;};
+	inline const char *md5() const {return Owner->StrP + S->md5sum;};
+	inline DescFileIterator FileList() const;
+
+	inline DescIterator() : Iterator<Description, DescIterator>() {};
+	inline DescIterator(pkgCache &Owner,Description *Trg = 0) : Iterator<Description, DescIterator>(Owner, Trg) {
+		if (S == 0)
+			S = Owner.DescP;
+	};
 };
 									/*}}}*/
 // Dependency iterator							/*{{{*/
-class pkgCache::DepIterator
-{
-   Dependency *Dep;
-   enum {DepVer, DepRev} Type;
-   pkgCache *Owner;
-   
-   void _dummy();
-   
-   public:
-
-   // Iteration
-   void operator ++(int) {if (Dep != Owner->DepP) Dep = Owner->DepP +
-	(Type == DepVer?Dep->NextDepends:Dep->NextRevDepends);};
-   inline void operator ++() {operator ++(0);};
-   inline bool end() const {return Owner == 0 || Dep == Owner->DepP?true:false;};
-   
-   // Comparison
-   inline bool operator ==(const DepIterator &B) const {return Dep == B.Dep;};
-   inline bool operator !=(const DepIterator &B) const {return Dep != B.Dep;};
-
-   // Accessors
-   inline Dependency *operator ->() {return Dep;};
-   inline Dependency const *operator ->() const {return Dep;};
-   inline Dependency &operator *() {return *Dep;};
-   inline Dependency const &operator *() const {return *Dep;};
-   inline operator Dependency *() {return Dep == Owner->DepP?0:Dep;};
-   inline operator Dependency const *() const {return Dep == Owner->DepP?0:Dep;};
-   inline pkgCache *Cache() {return Owner;};
-   
-   inline const char *TargetVer() const {return Dep->Version == 0?0:Owner->StrP + Dep->Version;};
-   inline PkgIterator TargetPkg() {return PkgIterator(*Owner,Owner->PkgP + Dep->Package);};
-   inline PkgIterator SmartTargetPkg() {PkgIterator R(*Owner,0);SmartTargetPkg(R);return R;};
-   inline VerIterator ParentVer() {return VerIterator(*Owner,Owner->VerP + Dep->ParentVer);};
-   inline PkgIterator ParentPkg() {return PkgIterator(*Owner,Owner->PkgP + Owner->VerP[Dep->ParentVer].ParentPkg);};
-   inline bool Reverse() {return Type == DepRev;};
-   inline unsigned long Index() const {return Dep - Owner->DepP;};
-   bool IsCritical();
-   void GlobOr(DepIterator &Start,DepIterator &End);
-   Version **AllTargets();   
-   bool SmartTargetPkg(PkgIterator &Result);
-   inline const char *CompType() {return Owner->CompType(Dep->CompareOp);};
-   inline const char *DepType() {return Owner->DepType(Dep->Type);};
-   
-   inline DepIterator(pkgCache &Owner,Dependency *Trg,Version * = 0) :
-          Dep(Trg), Type(DepVer), Owner(&Owner) 
-   {
-      if (Dep == 0)
-	 Dep = Owner.DepP;
-   };
-   inline DepIterator(pkgCache &Owner,Dependency *Trg,Package *) :
-          Dep(Trg), Type(DepRev), Owner(&Owner)
-   {
-      if (Dep == 0)
-	 Dep = Owner.DepP;
-   };
-   inline DepIterator() : Dep(0), Type(DepVer), Owner(0) {};
+class pkgCache::DepIterator : public Iterator<Dependency, DepIterator> {
+	enum {DepVer, DepRev} Type;
+
+	protected:
+	inline Dependency* OwnerPointer() const {
+		return Owner->DepP;
+	};
+
+	public:
+	// Iteration
+	void operator ++(int) {if (S != Owner->DepP) S = Owner->DepP +
+		(Type == DepVer ? S->NextDepends : S->NextRevDepends);};
+	inline void operator ++() {operator ++(0);};
+
+	// Accessors
+	inline const char *TargetVer() const {return S->Version == 0?0:Owner->StrP + S->Version;};
+	inline PkgIterator TargetPkg() {return PkgIterator(*Owner,Owner->PkgP + S->Package);};
+	inline PkgIterator SmartTargetPkg() {PkgIterator R(*Owner,0);SmartTargetPkg(R);return R;};
+	inline VerIterator ParentVer() {return VerIterator(*Owner,Owner->VerP + S->ParentVer);};
+	inline PkgIterator ParentPkg() {return PkgIterator(*Owner,Owner->PkgP + Owner->VerP[S->ParentVer].ParentPkg);};
+	inline bool Reverse() {return Type == DepRev;};
+	bool IsCritical();
+	void GlobOr(DepIterator &Start,DepIterator &End);
+	Version **AllTargets();
+	bool SmartTargetPkg(PkgIterator &Result);
+	inline const char *CompType() {return Owner->CompType(S->CompareOp);};
+	inline const char *DepType() {return Owner->DepType(S->Type);};
+
+	inline DepIterator(pkgCache &Owner, Dependency *Trg, Version* = 0) :
+		Iterator<Dependency, DepIterator>(Owner, Trg), Type(DepVer) {
+		if (S == 0)
+			S = Owner.DepP;
+	};
+	inline DepIterator(pkgCache &Owner, Dependency *Trg, Package*) :
+		Iterator<Dependency, DepIterator>(Owner, Trg), Type(DepRev) {
+		if (S == 0)
+			S = Owner.DepP;
+	};
+	inline DepIterator() : Iterator<Dependency, DepIterator>(), Type(DepVer) {};
 };
 									/*}}}*/
 // Provides iterator							/*{{{*/
-class pkgCache::PrvIterator
-{
-   Provides *Prv;
-   enum {PrvVer, PrvPkg} Type;
-   pkgCache *Owner;
-   
-   void _dummy();
-   
-   public:
-
-   // Iteration
-   void operator ++(int) {if (Prv != Owner->ProvideP) Prv = Owner->ProvideP +
-	(Type == PrvVer?Prv->NextPkgProv:Prv->NextProvides);};
-   inline void operator ++() {operator ++(0);};
-   inline bool end() const {return Owner == 0 || Prv == Owner->ProvideP?true:false;};
-   
-   // Comparison
-   inline bool operator ==(const PrvIterator &B) const {return Prv == B.Prv;};
-   inline bool operator !=(const PrvIterator &B) const {return Prv != B.Prv;};
-
-   // Accessors
-   inline Provides *operator ->() {return Prv;};
-   inline Provides const *operator ->() const {return Prv;};
-   inline Provides &operator *() {return *Prv;};
-   inline Provides const &operator *() const {return *Prv;};
-   inline operator Provides *() {return Prv == Owner->ProvideP?0:Prv;};
-   inline operator Provides const *() const {return Prv == Owner->ProvideP?0:Prv;};
-   inline pkgCache *Cache() {return Owner;};
-
-   inline const char *Name() const {return Owner->StrP + Owner->PkgP[Prv->ParentPkg].Name;};
-   inline const char *ProvideVersion() const {return Prv->ProvideVersion == 0?0:Owner->StrP + Prv->ProvideVersion;};
-   inline PkgIterator ParentPkg() {return PkgIterator(*Owner,Owner->PkgP + Prv->ParentPkg);};
-   inline VerIterator OwnerVer() {return VerIterator(*Owner,Owner->VerP + Prv->Version);};
-   inline PkgIterator OwnerPkg() {return PkgIterator(*Owner,Owner->PkgP + Owner->VerP[Prv->Version].ParentPkg);};
-   inline unsigned long Index() const {return Prv - Owner->ProvideP;};
-
-   inline PrvIterator() : Prv(0), Type(PrvVer), Owner(0)  {};
-
-   inline PrvIterator(pkgCache &Owner,Provides *Trg,Version *) :
-          Prv(Trg), Type(PrvVer), Owner(&Owner) 
-   {
-      if (Prv == 0)
-	 Prv = Owner.ProvideP;
-   };
-   inline PrvIterator(pkgCache &Owner,Provides *Trg,Package *) : 
-          Prv(Trg), Type(PrvPkg), Owner(&Owner)
-   {
-      if (Prv == 0)
-	 Prv = Owner.ProvideP;
-   };
+class pkgCache::PrvIterator : public Iterator<Provides, PrvIterator> {
+	enum {PrvVer, PrvPkg} Type;
+
+	protected:
+	inline Provides* OwnerPointer() const {
+		return Owner->ProvideP;
+	};
+
+	public:
+	// Iteration
+	void operator ++(int) {if (S != Owner->ProvideP) S = Owner->ProvideP +
+		(Type == PrvVer?S->NextPkgProv:S->NextProvides);};
+	inline void operator ++() {operator ++(0);};
+
+	// Accessors
+	inline const char *Name() const {return Owner->StrP + Owner->PkgP[S->ParentPkg].Name;};
+	inline const char *ProvideVersion() const {return S->ProvideVersion == 0?0:Owner->StrP + S->ProvideVersion;};
+	inline PkgIterator ParentPkg() {return PkgIterator(*Owner,Owner->PkgP + S->ParentPkg);};
+	inline VerIterator OwnerVer() {return VerIterator(*Owner,Owner->VerP + S->Version);};
+	inline PkgIterator OwnerPkg() {return PkgIterator(*Owner,Owner->PkgP + Owner->VerP[S->Version].ParentPkg);};
+
+	inline PrvIterator() : Iterator<Provides, PrvIterator>(), Type(PrvVer) {};
+
+	inline PrvIterator(pkgCache &Owner, Provides *Trg, Version*) :
+		Iterator<Provides, PrvIterator>(Owner, Trg), Type(PrvVer) {
+		if (S == 0)
+			S = Owner.ProvideP;
+	};
+	inline PrvIterator(pkgCache &Owner, Provides *Trg, Package*) :
+		Iterator<Provides, PrvIterator>(Owner, Trg), Type(PrvPkg) {
+		if (S == 0)
+			S = Owner.ProvideP;
+	};
 };
 									/*}}}*/
 // Package file								/*{{{*/
-class pkgCache::PkgFileIterator
-{
-   pkgCache *Owner;
-   PackageFile *File;
-
-   public:
-
-   // Iteration
-   void operator ++(int) {if (File!= Owner->PkgFileP) File = Owner->PkgFileP + File->NextFile;};
-   inline void operator ++() {operator ++(0);};
-   inline bool end() const {return Owner == 0 || File == Owner->PkgFileP?true:false;};
-
-   // Comparison
-   inline bool operator ==(const PkgFileIterator &B) const {return File == B.File;};
-   inline bool operator !=(const PkgFileIterator &B) const {return File != B.File;};
-			   
-   // Accessors
-   inline PackageFile *operator ->() {return File;};
-   inline PackageFile const *operator ->() const {return File;};
-   inline PackageFile const &operator *() const {return *File;};
-   inline operator PackageFile *() {return File == Owner->PkgFileP?0:File;};
-   inline operator PackageFile const *() const {return File == Owner->PkgFileP?0:File;};
-   inline pkgCache *Cache() {return Owner;};
-
-   inline const char *FileName() const {return File->FileName == 0?0:Owner->StrP + File->FileName;};
-   inline const char *Archive() const {return File->Archive == 0?0:Owner->StrP + File->Archive;};
-   inline const char *Component() const {return File->Component == 0?0:Owner->StrP + File->Component;};
-   inline const char *Version() const {return File->Version == 0?0:Owner->StrP + File->Version;};
-   inline const char *Origin() const {return File->Origin == 0?0:Owner->StrP + File->Origin;};
-   inline const char *Codename() const {return File->Codename ==0?0:Owner->StrP + File->Codename;};
-   inline const char *Label() const {return File->Label == 0?0:Owner->StrP + File->Label;};
-   inline const char *Site() const {return File->Site == 0?0:Owner->StrP + File->Site;};
-   inline const char *Architecture() const {return File->Architecture == 0?0:Owner->StrP + File->Architecture;};
-   inline const char *IndexType() const {return File->IndexType == 0?0:Owner->StrP + File->IndexType;};
-
-   inline unsigned long Index() const {return File - Owner->PkgFileP;};
-
-   bool IsOk();
-   string RelStr();
-   
-   // Constructors
-   inline PkgFileIterator() : Owner(0), File(0) {};
-   inline PkgFileIterator(pkgCache &Owner) : Owner(&Owner), File(Owner.PkgFileP) {};
-   inline PkgFileIterator(pkgCache &Owner,PackageFile *Trg) : Owner(&Owner), File(Trg) {};
+class pkgCache::PkgFileIterator : public Iterator<PackageFile, PkgFileIterator> {
+	protected:
+	inline PackageFile* OwnerPointer() const {
+		return Owner->PkgFileP;
+	};
+
+	public:
+	// Iteration
+	void operator ++(int) {if (S != Owner->PkgFileP) S = Owner->PkgFileP + S->NextFile;};
+	inline void operator ++() {operator ++(0);};
+
+	// Accessors
+	inline const char *FileName() const {return S->FileName == 0?0:Owner->StrP + S->FileName;};
+	inline const char *Archive() const {return S->Archive == 0?0:Owner->StrP + S->Archive;};
+	inline const char *Component() const {return S->Component == 0?0:Owner->StrP + S->Component;};
+	inline const char *Version() const {return S->Version == 0?0:Owner->StrP + S->Version;};
+	inline const char *Origin() const {return S->Origin == 0?0:Owner->StrP + S->Origin;};
+	inline const char *Codename() const {return S->Codename ==0?0:Owner->StrP + S->Codename;};
+	inline const char *Label() const {return S->Label == 0?0:Owner->StrP + S->Label;};
+	inline const char *Site() const {return S->Site == 0?0:Owner->StrP + S->Site;};
+	inline const char *Architecture() const {return S->Architecture == 0?0:Owner->StrP + S->Architecture;};
+	inline const char *IndexType() const {return S->IndexType == 0?0:Owner->StrP + S->IndexType;};
+
+	bool IsOk();
+	string RelStr();
+
+	// Constructors
+	inline PkgFileIterator() : Iterator<PackageFile, PkgFileIterator>() {};
+	inline PkgFileIterator(pkgCache &Owner) : Iterator<PackageFile, PkgFileIterator>(Owner, Owner.PkgFileP) {};
+	inline PkgFileIterator(pkgCache &Owner,PackageFile *Trg) : Iterator<PackageFile, PkgFileIterator>(Owner, Trg) {};
 };
 									/*}}}*/
 // Version File								/*{{{*/
-class pkgCache::VerFileIterator
-{
-   pkgCache *Owner;
-   VerFile *FileP;
-
-   public:
-
-   // Iteration
-   void operator ++(int) {if (FileP != Owner->VerFileP) FileP = Owner->VerFileP + FileP->NextFile;};
-   inline void operator ++() {operator ++(0);};
-   inline bool end() const {return Owner == 0 || FileP == Owner->VerFileP?true:false;};
-
-   // Comparison
-   inline bool operator ==(const VerFileIterator &B) const {return FileP == B.FileP;};
-   inline bool operator !=(const VerFileIterator &B) const {return FileP != B.FileP;};
-			   
-   // Accessors
-   inline VerFile *operator ->() {return FileP;};
-   inline VerFile const *operator ->() const {return FileP;};
-   inline VerFile const &operator *() const {return *FileP;};
-   inline operator VerFile *() {return FileP == Owner->VerFileP?0:FileP;};
-   inline operator VerFile const *() const {return FileP == Owner->VerFileP?0:FileP;};
-   inline pkgCache *Cache() {return Owner;};
-  
-   inline PkgFileIterator File() const {return PkgFileIterator(*Owner,FileP->File + Owner->PkgFileP);};
-   inline unsigned long Index() const {return FileP - Owner->VerFileP;};
-      
-   inline VerFileIterator() : Owner(0), FileP(0) {};
-   inline VerFileIterator(pkgCache &Owner,VerFile *Trg) : Owner(&Owner), FileP(Trg) {};
+class pkgCache::VerFileIterator : public pkgCache::Iterator<VerFile, VerFileIterator> {
+	protected:
+	inline VerFile* OwnerPointer() const {
+		return Owner->VerFileP;
+	};
+
+	public:
+	// Iteration
+	void operator ++(int) {if (S != Owner->VerFileP) S = Owner->VerFileP + S->NextFile;};
+	inline void operator ++() {operator ++(0);};
+
+	// Accessors
+	inline PkgFileIterator File() const {return PkgFileIterator(*Owner,S->File + Owner->PkgFileP);};
+
+	inline VerFileIterator() : Iterator<VerFile, VerFileIterator>() {};
+	inline VerFileIterator(pkgCache &Owner,VerFile *Trg) : Iterator<VerFile, VerFileIterator>(Owner, Trg) {};
 };
 									/*}}}*/
 // Description File							/*{{{*/
-class pkgCache::DescFileIterator
-{
-   pkgCache *Owner;
-   DescFile *FileP;
-
-   public:
-
-   // Iteration
-   void operator ++(int) {if (FileP != Owner->DescFileP) FileP = Owner->DescFileP + FileP->NextFile;};
-   inline void operator ++() {operator ++(0);};
-   inline bool end() const {return Owner == 0 ||  FileP == Owner->DescFileP?true:false;};
-
-   // Comparison
-   inline bool operator ==(const DescFileIterator &B) const {return FileP == B.FileP;};
-   inline bool operator !=(const DescFileIterator &B) const {return FileP != B.FileP;};
-			   
-   // Accessors
-   inline DescFile *operator ->() {return FileP;};
-   inline DescFile const *operator ->() const {return FileP;};
-   inline DescFile const &operator *() const {return *FileP;};
-   inline operator DescFile *() {return FileP == Owner->DescFileP?0:FileP;};
-   inline operator DescFile const *() const {return FileP == Owner->DescFileP?0:FileP;};
-   inline pkgCache *Cache() {return Owner;};
-  
-   inline PkgFileIterator File() const {return PkgFileIterator(*Owner,FileP->File + Owner->PkgFileP);};
-   inline unsigned long Index() const {return FileP - Owner->DescFileP;};
-      
-   inline DescFileIterator() : Owner(0), FileP(0) {};
-   inline DescFileIterator(pkgCache &Owner,DescFile *Trg) : Owner(&Owner), FileP(Trg) {};
+class pkgCache::DescFileIterator : public Iterator<DescFile, DescFileIterator> {
+	protected:
+	inline DescFile* OwnerPointer() const {
+		return Owner->DescFileP;
+	};
+
+	public:
+	// Iteration
+	void operator ++(int) {if (S != Owner->DescFileP) S = Owner->DescFileP + S->NextFile;};
+	inline void operator ++() {operator ++(0);};
+
+	// Accessors
+	inline PkgFileIterator File() const {return PkgFileIterator(*Owner,S->File + Owner->PkgFileP);};
+
+	inline DescFileIterator() : Iterator<DescFile, DescFileIterator>() {};
+	inline DescFileIterator(pkgCache &Owner,DescFile *Trg) : Iterator<DescFile, DescFileIterator>(Owner, Trg) {};
 };
 									/*}}}*/
 // Inlined Begin functions cant be in the class because of order problems /*{{{*/
+inline pkgCache::PkgIterator pkgCache::GrpIterator::PackageList() const
+       {return PkgIterator(*Owner,Owner->PkgP + S->FirstPackage);};
 inline pkgCache::VerIterator pkgCache::PkgIterator::VersionList() const
-       {return VerIterator(*Owner,Owner->VerP + Pkg->VersionList);};
+       {return VerIterator(*Owner,Owner->VerP + S->VersionList);};
 inline pkgCache::VerIterator pkgCache::PkgIterator::CurrentVer() const
-       {return VerIterator(*Owner,Owner->VerP + Pkg->CurrentVer);};
+       {return VerIterator(*Owner,Owner->VerP + S->CurrentVer);};
 inline pkgCache::DepIterator pkgCache::PkgIterator::RevDependsList() const
-       {return DepIterator(*Owner,Owner->DepP + Pkg->RevDepends,Pkg);};
+       {return DepIterator(*Owner,Owner->DepP + S->RevDepends,S);};
 inline pkgCache::PrvIterator pkgCache::PkgIterator::ProvidesList() const
-       {return PrvIterator(*Owner,Owner->ProvideP + Pkg->ProvidesList,Pkg);};
+       {return PrvIterator(*Owner,Owner->ProvideP + S->ProvidesList,S);};
 inline pkgCache::DescIterator pkgCache::VerIterator::DescriptionList() const
-       {return DescIterator(*Owner,Owner->DescP + Ver->DescriptionList);};
+       {return DescIterator(*Owner,Owner->DescP + S->DescriptionList);};
 inline pkgCache::PrvIterator pkgCache::VerIterator::ProvidesList() const
-       {return PrvIterator(*Owner,Owner->ProvideP + Ver->ProvidesList,Ver);};
+       {return PrvIterator(*Owner,Owner->ProvideP + S->ProvidesList,S);};
 inline pkgCache::DepIterator pkgCache::VerIterator::DependsList() const
-       {return DepIterator(*Owner,Owner->DepP + Ver->DependsList,Ver);};
+       {return DepIterator(*Owner,Owner->DepP + S->DependsList,S);};
 inline pkgCache::VerFileIterator pkgCache::VerIterator::FileList() const
-       {return VerFileIterator(*Owner,Owner->VerFileP + Ver->FileList);};
+       {return VerFileIterator(*Owner,Owner->VerFileP + S->FileList);};
 inline pkgCache::DescFileIterator pkgCache::DescIterator::FileList() const
-       {return DescFileIterator(*Owner,Owner->DescFileP + Desc->FileList);};
+       {return DescFileIterator(*Owner,Owner->DescFileP + S->FileList);};
 									/*}}}*/
 #endif

+ 15 - 22
apt-pkg/cdrom.cc

@@ -6,6 +6,8 @@
 #include<apt-pkg/cdromutl.h>
 #include<apt-pkg/strutl.h>
 #include<apt-pkg/cdrom.h>
+#include<apt-pkg/aptconfiguration.h>
+
 #include<sstream>
 #include<fstream>
 #include<config.h>
@@ -216,33 +218,23 @@ int pkgCdrom::Score(string Path)
 /* Here we drop everything that is not this machines arch */
 bool pkgCdrom::DropBinaryArch(vector<string> &List)
 {
-   char S[300];
-   snprintf(S,sizeof(S),"/binary-%s/",
-	    _config->Find("Apt::Architecture").c_str());
-   
+
    for (unsigned int I = 0; I < List.size(); I++)
    {
       const char *Str = List[I].c_str();
-      
-      const char *Res;
-      if ((Res = strstr(Str,"/binary-")) == 0)
+      const char *Start, *End;
+      if ((Start = strstr(Str,"/binary-")) == 0)
 	 continue;
 
-      // Weird, remove it.
-      if (strlen(Res) < strlen(S))
-      {
-	 List.erase(List.begin() + I);
-	 I--;
-	 continue;
-      }
-	  
-      // See if it is our arch
-      if (stringcmp(Res,Res + strlen(S),S) == 0)
-	 continue;
-      
-      // Erase it
+      // Between Start and End is the architecture
+      Start += 8;
+      if ((End = strstr(Start,"/")) != 0 && Start != End &&
+          APT::Configuration::checkArchitecture(string(Start, --End)) == true)
+	 continue; // okay, architecture is accepted
+
+      // not accepted -> Erase it
       List.erase(List.begin() + I);
-      I--;
+      --I; // the next entry is at the same index after the erase
    }
    
    return true;
@@ -289,7 +281,8 @@ bool pkgCdrom::DropRepeats(vector<string> &List,const char *Name)
 	 List[J] = string();
       }
    }  
- 
+   delete[] Inodes;
+
    // Wipe erased entries
    for (unsigned int I = 0; I < List.size();)
    {

+ 3 - 3
apt-pkg/clean.cc

@@ -12,6 +12,7 @@
 #include <apt-pkg/strutl.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/configuration.h>
+#include <apt-pkg/aptconfiguration.h>
 
 #include <apti18n.h>    
 
@@ -26,7 +27,6 @@
 bool pkgArchiveCleaner::Go(string Dir,pkgCache &Cache)
 {
    bool CleanInstalled = _config->FindB("APT::Clean-Installed",true);
-   string MyArch = _config->Find("APT::Architecture");
       
    DIR *D = opendir(Dir.c_str());
    if (D == 0)
@@ -75,9 +75,9 @@ bool pkgArchiveCleaner::Go(string Dir,pkgCache &Cache)
       for (I = Start; *I != 0 && *I != '.' ;I++);
       if (*I != '.')
 	 continue;
-      string Arch = DeQuoteString(string(Start,I-Start));
+      string const Arch = DeQuoteString(string(Start,I-Start));
       
-      if (Arch != "all" && Arch != MyArch)
+      if (APT::Configuration::checkArchitecture(Arch) == false)
 	 continue;
       
       // Lookup the package

+ 41 - 1
apt-pkg/contrib/cmndline.cc

@@ -135,7 +135,9 @@ bool CommandLine::Parse(int argc,const char **argv)
    for (; I != argc; I++)
       *Files++ = argv[I];
    *Files = 0;
-   
+
+   SaveInConfig(argc, argv);
+
    return true;
 }
 									/*}}}*/
@@ -351,3 +353,41 @@ bool CommandLine::DispatchArg(Dispatch *Map,bool NoMatch)
    return false;
 }
 									/*}}}*/
+// CommandLine::SaveInConfig - for output later in a logfile or so	/*{{{*/
+// ---------------------------------------------------------------------
+/* We save the commandline here to have it around later for e.g. logging.
+   It feels a bit like a hack here and isn't bulletproof, but it is better
+   than nothing after all. */
+void CommandLine::SaveInConfig(unsigned int const &argc, char const * const * const argv)
+{
+   char cmdline[300];
+   unsigned int length = 0;
+   bool lastWasOption = false;
+   bool closeQuote = false;
+   for (unsigned int i = 0; i < argc; ++i, ++length)
+   {
+      for (unsigned int j = 0; argv[i][j] != '\0' && length < sizeof(cmdline)-1; ++j, ++length)
+      {
+	 cmdline[length] = argv[i][j];
+	 if (lastWasOption == true && argv[i][j] == '=')
+	 {
+	    // That is possibly an option: Quote it if it includes spaces,
+	    // the benefit is that this will eliminate also most false positives
+	    const char* c = &argv[i][j+1];
+	    for (; *c != '\0' && *c != ' '; ++c);
+	    if (*c == '\0') continue;
+	    cmdline[++length] = '"';
+	    closeQuote = true;
+	 }
+      }
+      if (closeQuote == true)
+	 cmdline[length++] = '"';
+      // Problem: detects also --hello
+      if (cmdline[length-1] == 'o')
+	 lastWasOption = true;
+      cmdline[length] = ' ';
+   }
+   cmdline[--length] = '\0';
+   _config->Set("CommandLine::AsString", cmdline);
+}
+									/*}}}*/

+ 1 - 0
apt-pkg/contrib/cmndline.h

@@ -60,6 +60,7 @@ class CommandLine
    Configuration *Conf;
    bool HandleOpt(int &I,int argc,const char *argv[],
 		  const char *&Opt,Args *A,bool PreceedeMatch = false);
+   void static SaveInConfig(unsigned int const &argc, char const * const * const argv);
 
    public:
    

+ 4 - 4
apt-pkg/contrib/error.h

@@ -60,13 +60,13 @@ class GlobalError
    public:
 
    // Call to generate an error from a library call.
-   bool Errno(const char *Function,const char *Description,...) __like_printf_2 __cold;
-   bool WarningE(const char *Function,const char *Description,...) __like_printf_2 __cold;
+   bool Errno(const char *Function,const char *Description,...) __like_printf(3) __cold;
+   bool WarningE(const char *Function,const char *Description,...) __like_printf(3) __cold;
 
    /* A warning should be considered less severe than an error, and may be
       ignored by the client. */
-   bool Error(const char *Description,...) __like_printf_1 __cold;
-   bool Warning(const char *Description,...) __like_printf_1 __cold;
+   bool Error(const char *Description,...) __like_printf(2) __cold;
+   bool Warning(const char *Description,...) __like_printf(2) __cold;
 
    // Simple accessors
    inline bool PendingError() {return PendingFlag;};

+ 18 - 16
apt-pkg/contrib/macros.h

@@ -56,33 +56,35 @@
 
 // some nice optional GNUC features
 #if __GNUC__ >= 3
-        #define __must_check    __attribute__ ((warn_unused_result))
-        #define __deprecated    __attribute__ ((deprecated))
-        /* likely() and unlikely() can be used to mark boolean expressions
-           as (not) likely true which will help the compiler to optimise */
-        #define likely(x)       __builtin_expect (!!(x), 1)
-        #define unlikely(x)     __builtin_expect (!!(x), 0)
+	#define __must_check	__attribute__ ((warn_unused_result))
+	#define __deprecated	__attribute__ ((deprecated))
+	#define __attrib_const	__attribute__ ((__const__))
+	/* likely() and unlikely() can be used to mark boolean expressions
+	   as (not) likely true which will help the compiler to optimise */
+	#define likely(x)	__builtin_expect (!!(x), 1)
+	#define unlikely(x)	__builtin_expect (!!(x), 0)
 #else
-        #define __must_check    /* no warn_unused_result */
-        #define __deprecated    /* no deprecated */
-        #define likely(x)       (x)
-        #define unlikely(x)     (x)
+	#define __must_check	/* no warn_unused_result */
+	#define __deprecated	/* no deprecated */
+	#define __attrib_const	/* no const attribute */
+	#define likely(x)	(x)
+	#define unlikely(x)	(x)
 #endif
 
 // cold functions are unlikely() to be called
 #if (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) || __GNUC__ > 4
-        #define __cold  __attribute__ ((__cold__))
+	#define __cold	__attribute__ ((__cold__))
+	#define __hot	__attribute__ ((__hot__))
 #else
-        #define __cold  /* no cold marker */
+	#define __cold	/* no cold marker */
+	#define __hot	/* no hot marker */
 #endif
 
 #ifdef __GNUG__
 // Methods have a hidden this parameter that is visible to this attribute
-	#define __like_printf_1 __attribute__ ((format (printf, 2, 3)))
-	#define __like_printf_2 __attribute__ ((format (printf, 3, 4)))
+	#define __like_printf(n)	__attribute__((format(printf, n, n + 1)))
 #else
-	#define __like_printf_1
-	#define __like_printf_2
+	#define __like_printf(n)	/* no like-printf */
 #endif
 
 #endif

+ 59 - 11
apt-pkg/contrib/mmap.cc

@@ -27,6 +27,7 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <stdlib.h>
+#include <errno.h>
 
 #include <cstring>
    									/*}}}*/
@@ -35,7 +36,7 @@
 // ---------------------------------------------------------------------
 /* */
 MMap::MMap(FileFd &F,unsigned long Flags) : Flags(Flags), iSize(0),
-                     Base(0)
+                     Base(0), SyncToFd(NULL)
 {
    if ((Flags & NoImmMap) != NoImmMap)
       Map(F);
@@ -45,7 +46,7 @@ MMap::MMap(FileFd &F,unsigned long Flags) : Flags(Flags), iSize(0),
 // ---------------------------------------------------------------------
 /* */
 MMap::MMap(unsigned long Flags) : Flags(Flags), iSize(0),
-                     Base(0)
+                     Base(0), SyncToFd(NULL)
 {
 }
 									/*}}}*/
@@ -78,7 +79,24 @@ bool MMap::Map(FileFd &Fd)
    // Map it.
    Base = mmap(0,iSize,Prot,Map,Fd.Fd(),0);
    if (Base == (void *)-1)
-      return _error->Errno("mmap",_("Couldn't make mmap of %lu bytes"),iSize);
+   {
+      if (errno == ENODEV || errno == EINVAL)
+      {
+	 // The filesystem doesn't support this particular kind of mmap.
+	 // So we allocate a buffer and read the whole file into it.
+	 int const dupped_fd = dup(Fd.Fd());
+	 if (dupped_fd == -1)
+	    return _error->Errno("mmap", _("Couldn't duplicate file descriptor %i"), Fd.Fd());
+
+	 Base = new unsigned char[iSize];
+	 SyncToFd = new FileFd (dupped_fd);
+	 if (!SyncToFd->Seek(0L) || !SyncToFd->Read(Base, iSize))
+	    return false;
+      }
+      else
+	 return _error->Errno("mmap",_("Couldn't make mmap of %lu bytes"),
+	                      iSize);
+     }
 
    return true;
 }
@@ -93,10 +111,19 @@ bool MMap::Close(bool DoSync)
    
    if (DoSync == true)
       Sync();
-   
-   if (munmap((char *)Base,iSize) != 0)
-      _error->Warning("Unable to munmap");
-   
+
+   if (SyncToFd != NULL)
+   {
+      delete[] (char *)Base;
+      delete SyncToFd;
+      SyncToFd = NULL;
+   }
+   else
+   {
+      if (munmap((char *)Base, iSize) != 0)
+	 _error->WarningE("mmap", _("Unable to close mmap"));
+   }
+
    iSize = 0;
    Base = 0;
    return true;
@@ -113,8 +140,18 @@ bool MMap::Sync()
    
 #ifdef _POSIX_SYNCHRONIZED_IO   
    if ((Flags & ReadOnly) != ReadOnly)
-      if (msync((char *)Base,iSize,MS_SYNC) < 0)
-	 return _error->Errno("msync","Unable to write mmap");
+   {
+      if (SyncToFd != NULL)
+      {
+	 if (!SyncToFd->Seek(0) || !SyncToFd->Write(Base, iSize))
+	    return false;
+      }
+      else
+      {
+	 if (msync((char *)Base, iSize, MS_SYNC) < 0)
+	    return _error->Errno("msync", _("Unable to synchronize mmap"));
+      }
+   }
 #endif   
    return true;
 }
@@ -130,8 +167,19 @@ bool MMap::Sync(unsigned long Start,unsigned long Stop)
 #ifdef _POSIX_SYNCHRONIZED_IO
    unsigned long PSize = sysconf(_SC_PAGESIZE);
    if ((Flags & ReadOnly) != ReadOnly)
-      if (msync((char *)Base+(int)(Start/PSize)*PSize,Stop - Start,MS_SYNC) < 0)
-	 return _error->Errno("msync","Unable to write mmap");
+   {
+      if (SyncToFd != 0)
+      {
+	 if (!SyncToFd->Seek(0) ||
+	     !SyncToFd->Write (((char *)Base)+Start, Stop-Start))
+	    return false;
+      }
+      else
+      {
+	 if (msync((char *)Base+(int)(Start/PSize)*PSize,Stop - Start,MS_SYNC) < 0)
+	    return _error->Errno("msync", _("Unable to synchronize mmap"));
+      }
+   }
 #endif   
    return true;
 }

+ 5 - 0
apt-pkg/contrib/mmap.h

@@ -44,6 +44,11 @@ class MMap
    unsigned long iSize;
    void *Base;
 
+   // In case mmap can not be used, we keep a dup of the file
+   // descriptor that should have been mmaped so that we can write to
+   // the file in Sync().
+   FileFd *SyncToFd;
+
    bool Map(FileFd &Fd);
    bool Close(bool DoSync = true);
    

+ 44 - 32
apt-pkg/contrib/strutl.cc

@@ -198,7 +198,8 @@ bool ParseQuoteWord(const char *&String,string &Res)
    char *I;
    for (I = Buffer; I < Buffer + sizeof(Buffer) && Start != C; I++)
    {
-      if (*Start == '%' && Start + 2 < C)
+      if (*Start == '%' && Start + 2 < C &&
+	  isxdigit(Start[1]) && isxdigit(Start[2]))
       {
 	 Tmp[0] = Start[1];
 	 Tmp[1] = Start[2];
@@ -273,7 +274,8 @@ string QuoteString(const string &Str, const char *Bad)
    for (string::const_iterator I = Str.begin(); I != Str.end(); I++)
    {
       if (strchr(Bad,*I) != 0 || isprint(*I) == 0 || 
-	  *I <= 0x20 || *I >= 0x7F)
+	  *I == 0x25 || // percent '%' char
+	  *I <= 0x20 || *I >= 0x7F) // control chars
       {
 	 char Buf[10];
 	 sprintf(Buf,"%%%02x",(int)*I);
@@ -289,11 +291,17 @@ string QuoteString(const string &Str, const char *Bad)
 // ---------------------------------------------------------------------
 /* This undoes QuoteString */
 string DeQuoteString(const string &Str)
+{
+   return DeQuoteString(Str.begin(),Str.end());
+}
+string DeQuoteString(string::const_iterator const &begin,
+			string::const_iterator const &end)
 {
    string Res;
-   for (string::const_iterator I = Str.begin(); I != Str.end(); I++)
+   for (string::const_iterator I = begin; I != end; I++)
    {
-      if (*I == '%' && I + 2 < Str.end())
+      if (*I == '%' && I + 2 < end &&
+	  isxdigit(I[1]) && isxdigit(I[2]))
       {
 	 char Tmp[3];
 	 Tmp[0] = I[1];
@@ -566,7 +574,7 @@ int stringcmp(string::const_iterator A,string::const_iterator AEnd,
 int stringcasecmp(const char *A,const char *AEnd,const char *B,const char *BEnd)
 {
    for (; A != AEnd && B != BEnd; A++, B++)
-      if (toupper(*A) != toupper(*B))
+      if (tolower_ascii(*A) != tolower_ascii(*B))
 	 break;
 
    if (A == AEnd && B == BEnd)
@@ -575,7 +583,7 @@ int stringcasecmp(const char *A,const char *AEnd,const char *B,const char *BEnd)
       return 1;
    if (B == BEnd)
       return -1;
-   if (toupper(*A) < toupper(*B))
+   if (tolower_ascii(*A) < tolower_ascii(*B))
       return -1;
    return 1;
 }
@@ -584,7 +592,7 @@ int stringcasecmp(string::const_iterator A,string::const_iterator AEnd,
 		  const char *B,const char *BEnd)
 {
    for (; A != AEnd && B != BEnd; A++, B++)
-      if (toupper(*A) != toupper(*B))
+      if (tolower_ascii(*A) != tolower_ascii(*B))
 	 break;
 
    if (A == AEnd && B == BEnd)
@@ -593,7 +601,7 @@ int stringcasecmp(string::const_iterator A,string::const_iterator AEnd,
       return 1;
    if (B == BEnd)
       return -1;
-   if (toupper(*A) < toupper(*B))
+   if (tolower_ascii(*A) < tolower_ascii(*B))
       return -1;
    return 1;
 }
@@ -601,7 +609,7 @@ int stringcasecmp(string::const_iterator A,string::const_iterator AEnd,
 		  string::const_iterator B,string::const_iterator BEnd)
 {
    for (; A != AEnd && B != BEnd; A++, B++)
-      if (toupper(*A) != toupper(*B))
+      if (tolower_ascii(*A) != tolower_ascii(*B))
 	 break;
 
    if (A == AEnd && B == BEnd)
@@ -610,7 +618,7 @@ int stringcasecmp(string::const_iterator A,string::const_iterator AEnd,
       return 1;
    if (B == BEnd)
       return -1;
-   if (toupper(*A) < toupper(*B))
+   if (tolower_ascii(*A) < tolower_ascii(*B))
       return -1;
    return 1;
 }
@@ -789,28 +797,28 @@ bool ReadMessages(int Fd, vector<string> &List)
 // MonthConv - Converts a month string into a number			/*{{{*/
 // ---------------------------------------------------------------------
 /* This was lifted from the boa webserver which lifted it from 'wn-v1.07'
-   Made it a bit more robust with a few touppers though. */
+   Made it a bit more robust with a few tolower_ascii though. */
 static int MonthConv(char *Month)
 {
-   switch (toupper(*Month)) 
+   switch (tolower_ascii(*Month)) 
    {
-      case 'A':
-      return toupper(Month[1]) == 'P'?3:7;
-      case 'D':
+      case 'a':
+      return tolower_ascii(Month[1]) == 'p'?3:7;
+      case 'd':
       return 11;
-      case 'F':
+      case 'f':
       return 1;
-      case 'J':
-      if (toupper(Month[1]) == 'A')
+      case 'j':
+      if (tolower_ascii(Month[1]) == 'a')
 	 return 0;
-      return toupper(Month[2]) == 'N'?5:6;
-      case 'M':
-      return toupper(Month[2]) == 'R'?2:4;
-      case 'N':
+      return tolower_ascii(Month[2]) == 'n'?5:6;
+      case 'm':
+      return tolower_ascii(Month[2]) == 'r'?2:4;
+      case 'n':
       return 10;
-      case 'O':
+      case 'o':
       return 9;
-      case 'S':
+      case 's':
       return 8;
 
       // Pretend it is January..
@@ -1000,12 +1008,12 @@ bool TokSplitString(char Tok,char *Input,char **List,
    return true;
 }
 									/*}}}*/
-// ExplodeString - Split a string up into a vector			/*{{{*/
+// VectorizeString - Split a string up into a vector of strings		/*{{{*/
 // ---------------------------------------------------------------------
 /* This can be used to split a given string up into a vector, so the
    propose is the same as in the method above and this one is a bit slower
-   also, but the advantage is that we an iteratable vector */
-vector<string> ExplodeString(string const &haystack, char const &split)
+   also, but the advantage is that we have an iteratable vector */
+vector<string> VectorizeString(string const &haystack, char const &split)
 {
    string::const_iterator start = haystack.begin();
    string::const_iterator end = start;
@@ -1133,10 +1141,13 @@ char *safe_snprintf(char *Buffer,char *End,const char *Format,...)
 
 // tolower_ascii - tolower() function that ignores the locale		/*{{{*/
 // ---------------------------------------------------------------------
-/* */
-int tolower_ascii(int c)
+/* This little function is the most called method we have and tries
+   therefore to do the absolut minimum - and is noteable faster than
+   standard tolower/toupper and as a bonus avoids problems with different
+   locales - we only operate on ascii chars anyway. */
+int tolower_ascii(int const c)
 {
-   if (c >= 'A' and c <= 'Z')
+   if (c >= 'A' && c <= 'Z')
       return c + 32;
    return c;
 }
@@ -1235,9 +1246,10 @@ void URI::CopyFrom(const string &U)
    else
    {
       Host.assign(At+1,SingleSlash);
-      User.assign(FirstColon,SecondColon);
+      // username and password must be encoded (RFC 3986)
+      User.assign(DeQuoteString(FirstColon,SecondColon));
       if (SecondColon < At)
-	 Password.assign(SecondColon+1,At);
+	 Password.assign(DeQuoteString(SecondColon+1,At));
    }   
    
    // Now we parse the RFC 2732 [] hostnames.

+ 8 - 16
apt-pkg/contrib/strutl.h

@@ -25,19 +25,12 @@
 #include <iostream>
 #include <time.h>
 
+#include "macros.h"
+
 using std::string;
 using std::vector;
 using std::ostream;
 
-#ifdef __GNUG__
-// Methods have a hidden this parameter that is visible to this attribute
-#define APT_FORMAT2 __attribute__ ((format (printf, 2, 3)))
-#define APT_FORMAT3 __attribute__ ((format (printf, 3, 4)))
-#else
-#define APT_FORMAT2
-#define APT_FORMAT3
-#endif    
-
 bool UTF8ToCodeset(const char *codeset, const string &orig, string *dest);
 char *_strstrip(char *String);
 char *_strtabexpand(char *String,size_t Len);
@@ -45,6 +38,7 @@ bool ParseQuoteWord(const char *&String,string &Res);
 bool ParseCWord(const char *&String,string &Res);
 string QuoteString(const string &Str,const char *Bad);
 string DeQuoteString(const string &Str);
+string DeQuoteString(string::const_iterator const &begin, string::const_iterator const &end);
 string SizeToStr(double Bytes);
 string TimeToStr(unsigned long Sec);
 string Base64Encode(const string &Str);
@@ -59,12 +53,12 @@ bool StrToNum(const char *Str,unsigned long &Res,unsigned Len,unsigned Base = 0)
 bool Hex2Num(const string &Str,unsigned char *Num,unsigned int Length);
 bool TokSplitString(char Tok,char *Input,char **List,
 		    unsigned long ListMax);
-vector<string> ExplodeString(string const &haystack, char const &split);
-void ioprintf(ostream &out,const char *format,...) APT_FORMAT2;
-void strprintf(string &out,const char *format,...) APT_FORMAT2;
-char *safe_snprintf(char *Buffer,char *End,const char *Format,...) APT_FORMAT3;
+vector<string> VectorizeString(string const &haystack, char const &split) __attrib_const;
+void ioprintf(ostream &out,const char *format,...) __like_printf(2);
+void strprintf(string &out,const char *format,...) __like_printf(2);
+char *safe_snprintf(char *Buffer,char *End,const char *Format,...) __like_printf(3);
 bool CheckDomainList(const string &Host, const string &List);
-int tolower_ascii(int c);
+int tolower_ascii(int const c) __attrib_const __hot;
 
 #define APT_MKSTRCMP(name,func) \
 inline int name(const char *A,const char *B) {return func(A,A+strlen(A),B,B+strlen(B));}; \
@@ -144,6 +138,4 @@ struct RxChoiceList
 unsigned long RegexChoice(RxChoiceList *Rxs,const char **ListBegin,
 		      const char **ListEnd);
 
-#undef APT_FORMAT2
-
 #endif

+ 11 - 4
apt-pkg/deb/debindexfile.cc

@@ -149,9 +149,12 @@ unsigned long debSourcesIndex::Size() const
 // PackagesIndex::debPackagesIndex - Contructor				/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-debPackagesIndex::debPackagesIndex(string URI,string Dist,string Section,bool Trusted) : 
-                  pkgIndexFile(Trusted), URI(URI), Dist(Dist), Section(Section)
+debPackagesIndex::debPackagesIndex(string const &URI, string const &Dist, string const &Section,
+					bool const &Trusted, string const &Arch) :
+                  pkgIndexFile(Trusted), URI(URI), Dist(Dist), Section(Section), Architecture(Arch)
 {
+	if (Architecture == "native")
+		Architecture = _config->Find("APT::Architecture");
 }
 									/*}}}*/
 // PackagesIndex::ArchiveInfo - Short version of the archive url	/*{{{*/
@@ -171,6 +174,8 @@ string debPackagesIndex::ArchiveInfo(pkgCache::VerIterator Ver) const
    Res += " ";
    Res += Ver.ParentPkg().Name();
    Res += " ";
+   Res += Ver.Arch();
+   Res += " ";
    Res += Ver.VerStr();
    return Res;
 }
@@ -204,6 +209,8 @@ string debPackagesIndex::Info(const char *Type) const
    else
       Info += Dist + '/' + Section;   
    Info += " ";
+   Info += Architecture;
+   Info += " ";
    Info += Type;
    return Info;
 }
@@ -227,7 +234,7 @@ string debPackagesIndex::IndexURI(const char *Type) const
    }
    else
       Res = URI + "dists/" + Dist + '/' + Section +
-      "/binary-" + _config->Find("APT::Architecture") + '/';
+      "/binary-" + Architecture + '/';
    
    Res += Type;
    return Res;
@@ -259,7 +266,7 @@ bool debPackagesIndex::Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const
 {
    string PackageFile = IndexFile("Packages");
    FileFd Pkg(PackageFile,FileFd::ReadOnly);
-   debListParser Parser(&Pkg);
+   debListParser Parser(&Pkg, Architecture);
    if (_error->PendingError() == true)
       return _error->Error("Problem opening %s",PackageFile.c_str());
    

+ 3 - 1
apt-pkg/deb/debindexfile.h

@@ -46,6 +46,7 @@ class debPackagesIndex : public pkgIndexFile
    string URI;
    string Dist;
    string Section;
+   string Architecture;
 
    string Info(const char *Type) const;
    string IndexFile(const char *Type) const;
@@ -69,7 +70,8 @@ class debPackagesIndex : public pkgIndexFile
    virtual bool Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const;
    virtual pkgCache::PkgFileIterator FindInCache(pkgCache &Cache) const;
 
-   debPackagesIndex(string URI,string Dist,string Section,bool Trusted);
+   debPackagesIndex(string const &URI, string const &Dist, string const &Section,
+			bool const &Trusted, string const &Arch = "native");
 };
 
 class debTranslationsIndex : public pkgIndexFile

+ 175 - 44
apt-pkg/deb/deblistparser.cc

@@ -31,10 +31,13 @@ static debListParser::WordList PrioList[] = {{"important",pkgCache::State::Impor
 
 // ListParser::debListParser - Constructor				/*{{{*/
 // ---------------------------------------------------------------------
-/* */
-debListParser::debListParser(FileFd *File) : Tags(File)
-{
-   Arch = _config->Find("APT::architecture");
+/* Provide an architecture and only this one and "all" will be accepted
+   in Step(), if no Architecture is given we will accept every arch
+   we would accept in general with checkArchitecture() */
+debListParser::debListParser(FileFd *File, string const &Arch) : Tags(File),
+				Arch(Arch) {
+   if (Arch == "native")
+      this->Arch = _config->Find("APT::Architecture");
 }
 									/*}}}*/
 // ListParser::UniqFindTagWrite - Find the tag and write a unq string	/*{{{*/
@@ -52,14 +55,41 @@ unsigned long debListParser::UniqFindTagWrite(const char *Tag)
 // ListParser::Package - Return the package name			/*{{{*/
 // ---------------------------------------------------------------------
 /* This is to return the name of the package this section describes */
-string debListParser::Package()
-{
-   string Result = Section.FindS("Package");
-   if (Result.empty() == true)
+string debListParser::Package() {
+   string const Result = Section.FindS("Package");
+   if(unlikely(Result.empty() == true))
       _error->Error("Encountered a section with no Package: header");
    return Result;
 }
 									/*}}}*/
+// ListParser::Architecture - Return the package arch			/*{{{*/
+// ---------------------------------------------------------------------
+/* This will return the Architecture of the package this section describes
+   Note that architecture "all" packages will get the architecture of the
+   Packages file parsed here. */
+string debListParser::Architecture() {
+   string const Result = Section.FindS("Architecture");
+   if (Result.empty() == true || Result == "all")
+   {
+      if (Arch.empty() == true)
+	 /* FIXME: this is a problem for installed arch all
+	    packages as we don't know from which arch this
+	    package was installed - and therefore which
+	    dependency this package resolves. */
+	 return _config->Find("APT::Architecture");
+      else
+	 return Arch;
+   }
+   return Result;
+}
+									/*}}}*/
+// ListParser::ArchitectureAll						/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool debListParser::ArchitectureAll() {
+   return Section.FindS("Architecture") == "all";
+}
+									/*}}}*/
 // ListParser::Version - Return the version string			/*{{{*/
 // ---------------------------------------------------------------------
 /* This is to return the string describing the version in debian form,
@@ -77,8 +107,31 @@ bool debListParser::NewVersion(pkgCache::VerIterator Ver)
 {
    // Parse the section
    Ver->Section = UniqFindTagWrite("Section");
-   Ver->Arch = UniqFindTagWrite("Architecture");
-   
+
+   // Parse multi-arch
+   if (Section.FindS("Architecture") == "all")
+      /* Arch all packages can't have a Multi-Arch field,
+         but we need a special treatment for them nonetheless */
+      Ver->MultiArch = pkgCache::Version::All;
+   else
+   {
+      string const MultiArch = Section.FindS("Multi-Arch");
+      if (MultiArch.empty() == true)
+	 Ver->MultiArch = pkgCache::Version::None;
+      else if (MultiArch == "same")
+	 Ver->MultiArch = pkgCache::Version::Same;
+      else if (MultiArch == "foreign")
+	 Ver->MultiArch = pkgCache::Version::Foreign;
+      else if (MultiArch == "allowed")
+	 Ver->MultiArch = pkgCache::Version::Allowed;
+      else
+      {
+	 _error->Warning("Unknown Multi-Arch type »%s« for package »%s«",
+			MultiArch.c_str(), Section.FindS("Package").c_str());
+	 Ver->MultiArch = pkgCache::Version::None;
+      }
+   }
+
    // Archive Size
    Ver->Size = (unsigned)Section.FindI("Size");
    
@@ -95,6 +148,25 @@ bool debListParser::NewVersion(pkgCache::VerIterator Ver)
 	 Ver->Priority = pkgCache::State::Extra;
    }
 
+   if (Ver->MultiArch == pkgCache::Version::All)
+   {
+      /* We maintain a "pseudo" arch=all package for architecture all versions
+	 on which these versions can depend on. This pseudo package is many used
+	 for downloading/installing: The other pseudo-packages will degenerate
+	 to a NOP in the download/install step - this package will ensure that
+	 it is downloaded only one time and installed only one time -- even if
+	 the architecture bound versions coming in and out on regular basis. */
+      bool const static multiArch = APT::Configuration::getArchitectures().size() > 1;
+      if (strcmp(Ver.Arch(true),"all") == 0)
+	 return true;
+      else if (multiArch == true)
+      {
+	 // our pseudo packages have no size to not confuse the fetcher
+	 Ver->Size = 0;
+	 Ver->InstalledSize = 0;
+      }
+   }
+
    if (ParseDepends(Ver,"Depends",pkgCache::Dep::Depends) == false)
       return false;
    if (ParseDepends(Ver,"Pre-Depends",pkgCache::Dep::PreDepends) == false)
@@ -183,8 +255,16 @@ bool debListParser::UsePackage(pkgCache::PkgIterator Pkg,
 {
    if (Pkg->Section == 0)
       Pkg->Section = UniqFindTagWrite("Section");
-   if (Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false)
-      return false;
+
+   // Packages which are not from the "native" arch doesn't get the essential flag
+   // in the default "native" mode - it is also possible to mark "all" or "none".
+   // The "installed" mode is handled by ParseStatus(), See #544481 and friends.
+   string const static myArch = _config->Find("APT::Architecture");
+   string const static essential = _config->Find("pkgCacheGen::Essential", "native");
+   if ((essential == "native" && Pkg->Arch != 0 && myArch == Pkg.Arch()) ||
+       essential == "all")
+      if (Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false)
+	 return false;
    if (Section.FindFlag("Important",Pkg->Flags,pkgCache::Flag::Important) == false)
       return false;
 
@@ -258,7 +338,13 @@ bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg,
    const char *Stop;
    if (Section.Find("Status",Start,Stop) == false)
       return true;
-   
+
+   // UsePackage() is responsible for setting the flag in the default case
+   bool const static essential = _config->Find("pkgCacheGen::Essential", "") == "installed";
+   if (essential == true &&
+       Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false)
+      return false;
+
    // Isolate the first word
    const char *I = Start;
    for(; I < Stop && *I != ' '; I++);
@@ -534,8 +620,12 @@ bool debListParser::ParseDepends(pkgCache::VerIterator Ver,
    const char *Stop;
    if (Section.Find(Tag,Start,Stop) == false)
       return true;
-   
+
+   static std::vector<std::string> const archs = APT::Configuration::getArchitectures();
+   static bool const multiArch = archs.size() <= 1;
+
    string Package;
+   string const pkgArch = Ver.Arch(true);
    string Version;
    unsigned int Op;
 
@@ -544,8 +634,18 @@ bool debListParser::ParseDepends(pkgCache::VerIterator Ver,
       Start = ParseDepends(Start,Stop,Package,Version,Op);
       if (Start == 0)
 	 return _error->Error("Problem parsing dependency %s",Tag);
-      
-      if (NewDepends(Ver,Package,Version,Op,Type) == false)
+
+      if (multiArch == true &&
+	  (Type == pkgCache::Dep::Conflicts ||
+	   Type == pkgCache::Dep::DpkgBreaks ||
+	   Type == pkgCache::Dep::Replaces))
+      {
+	 for (std::vector<std::string>::const_iterator a = archs.begin();
+	      a != archs.end(); ++a)
+	    if (NewDepends(Ver,Package,*a,Version,Op,Type) == false)
+	       return false;
+      }
+      else if (NewDepends(Ver,Package,pkgArch,Version,Op,Type) == false)
 	 return false;
       if (Start == Stop)
 	 break;
@@ -560,29 +660,52 @@ bool debListParser::ParseProvides(pkgCache::VerIterator Ver)
 {
    const char *Start;
    const char *Stop;
-   if (Section.Find("Provides",Start,Stop) == false)
-      return true;
-   
-   string Package;
-   string Version;
-   unsigned int Op;
-
-   while (1)
+   if (Section.Find("Provides",Start,Stop) == true)
    {
-      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());
-      } else {
-	 if (NewProvides(Ver,Package,Version) == false)
-	    return false;
+      string Package;
+      string Version;
+      string const Arch = Ver.Arch(true);
+      unsigned int Op;
+
+      while (1)
+      {
+	 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());
+	 } else {
+	    if (NewProvides(Ver, Package, Arch, Version) == false)
+	       return false;
+	 }
+
+	 if (Start == Stop)
+	    break;
       }
+   }
 
-      if (Start == Stop)
-	 break;
+   if (Ver->MultiArch == pkgCache::Version::Allowed)
+   {
+      string const Package = string(Ver.ParentPkg().Name()).append(":").append("any");
+      NewProvides(Ver, Package, "any", Ver.VerStr());
    }
-   
+
+   if (Ver->MultiArch != pkgCache::Version::Foreign)
+      return true;
+
+   std::vector<string> const archs = APT::Configuration::getArchitectures();
+   if (archs.size() <= 1)
+      return true;
+
+   string const Package = Ver.ParentPkg().Name();
+   string const Version = Ver.VerStr();
+   for (std::vector<string>::const_iterator a = archs.begin();
+	a != archs.end(); ++a)
+   {
+      if (NewProvides(Ver, Package, *a, Version) == false)
+	 return false;
+   }
+
    return true;
 }
 									/*}}}*/
@@ -613,16 +736,23 @@ bool debListParser::Step()
       /* See if this is the correct Architecture, if it isn't then we
          drop the whole section. A missing arch tag only happens (in theory)
          inside the Status file, so that is a positive return */
-      const char *Start;
-      const char *Stop;
-      if (Section.Find("Architecture",Start,Stop) == false)
+      string const Architecture = Section.FindS("Architecture");
+      if (Architecture.empty() == true)
 	 return true;
 
-      if (stringcmp(Arch,Start,Stop) == 0)
-	 return true;
+      if (Arch.empty() == true)
+      {
+	 if (APT::Configuration::checkArchitecture(Architecture) == true)
+	    return true;
+      }
+      else
+      {
+	 if (Architecture == Arch)
+	    return true;
 
-      if (stringcmp(Start,Stop,"all") == 0)
-	 return true;
+	 if (Architecture == "all")
+	    return true;
+      }
 
       iOffset = Tags.Offset();
    }   
@@ -640,8 +770,9 @@ bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI,
    if (Tags.Step(Section) == false)
       return false;
 
-   //mvo: I don't think we need to fill that in (it's unused since apt-0.6)
-   //FileI->Architecture = WriteUniqString(Arch);
+   // FIXME: Do we need it now for multi-arch?
+   // mvo: I don't think we need to fill that in (it's unused since apt-0.6)
+//    FileI->Architecture = WriteUniqString(Arch);
    
    // apt-secure does no longer download individual (per-section) Release
    // file. to provide Component pinning we use the section name now

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

@@ -46,6 +46,8 @@ class debListParser : public pkgCacheGenerator::ListParser
       
    // These all operate against the current section
    virtual string Package();
+   virtual string Architecture();
+   virtual bool ArchitectureAll();
    virtual string Version();
    virtual bool NewVersion(pkgCache::VerIterator Ver);
    virtual string Description();
@@ -68,7 +70,7 @@ class debListParser : public pkgCacheGenerator::ListParser
 			    bool const &StripMultiArch = false);
    static const char *ConvertRelation(const char *I,unsigned int &Op);
 
-   debListParser(FileFd *File);
+   debListParser(FileFd *File, string const &Arch = "");
 };
 
 #endif

+ 186 - 112
apt-pkg/deb/debmetaindex.cc

@@ -8,9 +8,11 @@
 #include <apt-pkg/aptconfiguration.h>
 #include <apt-pkg/error.h>
 
+#include <set>
+
 using namespace std;
 
-string debReleaseIndex::Info(const char *Type, const string Section) const
+string debReleaseIndex::Info(const char *Type, string const &Section, string const &Arch) const
 {
    string Info = ::URI::SiteOnly(URI) + ' ';
    if (Dist[Dist.size() - 1] == '/')
@@ -19,7 +21,11 @@ string debReleaseIndex::Info(const char *Type, const string Section) const
          Info += Dist;
    }
    else
-      Info += Dist + '/' + Section;   
+   {
+      Info += Dist + '/' + Section;
+      if (Arch.empty() == true)
+	 Info += " " + Arch;
+   }
    Info += " ";
    Info += Type;
    return Info;
@@ -61,16 +67,21 @@ string debReleaseIndex::MetaIndexURI(const char *Type) const
    return Res;
 }
 
-string debReleaseIndex::IndexURISuffix(const char *Type, const string Section) const
+string debReleaseIndex::IndexURISuffix(const char *Type, string const &Section, string const &Arch) const
 {
    string Res ="";
    if (Dist[Dist.size() - 1] != '/')
-      Res += Section + "/binary-" + _config->Find("APT::Architecture") + '/';
+   {
+      if (Arch == "native")
+	 Res += Section + "/binary-" + _config->Find("APT::Architecture") + '/';
+      else
+	 Res += Section + "/binary-" + Arch + '/';
+   }
    return Res + Type;
 }
    
 
-string debReleaseIndex::IndexURI(const char *Type, const string Section) const
+string debReleaseIndex::IndexURI(const char *Type, string const &Section, string const &Arch) const
 {
    if (Dist[Dist.size() - 1] == '/')
    {
@@ -82,10 +93,10 @@ string debReleaseIndex::IndexURI(const char *Type, const string Section) const
       return Res + Type;
    }
    else
-      return URI + "dists/" + Dist + '/' + IndexURISuffix(Type, Section);
+      return URI + "dists/" + Dist + '/' + IndexURISuffix(Type, Section, Arch);
  }
 
-string debReleaseIndex::SourceIndexURISuffix(const char *Type, const string Section) const
+string debReleaseIndex::SourceIndexURISuffix(const char *Type, const string &Section) const
 {
    string Res ="";
    if (Dist[Dist.size() - 1] != '/')
@@ -93,7 +104,7 @@ string debReleaseIndex::SourceIndexURISuffix(const char *Type, const string Sect
    return Res + Type;
 }
 
-string debReleaseIndex::SourceIndexURI(const char *Type, const string Section) const
+string debReleaseIndex::SourceIndexURI(const char *Type, const string &Section) const
 {
    string Res;
    if (Dist[Dist.size() - 1] == '/')
@@ -108,44 +119,61 @@ string debReleaseIndex::SourceIndexURI(const char *Type, const string Section) c
       return URI + "dists/" + Dist + "/" + SourceIndexURISuffix(Type, Section);
 }
 
-debReleaseIndex::debReleaseIndex(string URI,string Dist)
-{
-   this->URI = URI;
-   this->Dist = Dist;
-   this->Indexes = NULL;
-   this->Type = "deb";
+debReleaseIndex::debReleaseIndex(string const &URI, string const &Dist) {
+	this->URI = URI;
+	this->Dist = Dist;
+	this->Indexes = NULL;
+	this->Type = "deb";
 }
 
-debReleaseIndex::~debReleaseIndex()
-{
-   for (vector<const debSectionEntry *>::const_iterator I = SectionEntries.begin();
-	I != SectionEntries.end(); I++)
-      delete *I;
+debReleaseIndex::~debReleaseIndex() {
+	for (map<string, vector<debSectionEntry const*> >::const_iterator A = ArchEntries.begin();
+	     A != ArchEntries.end(); ++A)
+		for (vector<const debSectionEntry *>::const_iterator S = A->second.begin();
+		     S != A->second.end(); ++S)
+			delete *S;
 }
 
-vector <struct IndexTarget *>* debReleaseIndex::ComputeIndexTargets() const
-{
-   vector <struct IndexTarget *>* IndexTargets = new vector <IndexTarget *>;
-   for (vector <const debSectionEntry *>::const_iterator I = SectionEntries.begin();
-	I != SectionEntries.end();
-	I++)
-   {
-      IndexTarget * Target = new IndexTarget();
-      Target->ShortDesc = (*I)->IsSrc ? "Sources" : "Packages";
-      Target->MetaKey
-	= (*I)->IsSrc ? SourceIndexURISuffix(Target->ShortDesc.c_str(), (*I)->Section)
-	              : IndexURISuffix(Target->ShortDesc.c_str(), (*I)->Section);
-      Target->URI 
-	= (*I)->IsSrc ? SourceIndexURI(Target->ShortDesc.c_str(), (*I)->Section)
-	              : IndexURI(Target->ShortDesc.c_str(), (*I)->Section);
-      
-      Target->Description = Info (Target->ShortDesc.c_str(), (*I)->Section);
-      IndexTargets->push_back (Target);
-   }
-   return IndexTargets;
+vector <struct IndexTarget *>* debReleaseIndex::ComputeIndexTargets() const {
+	vector <struct IndexTarget *>* IndexTargets = new vector <IndexTarget *>;
+
+	map<string, vector<debSectionEntry const*> >::const_iterator const src = ArchEntries.find("source");
+	if (src != ArchEntries.end()) {
+		vector<debSectionEntry const*> const SectionEntries = src->second;
+		for (vector<debSectionEntry const*>::const_iterator I = SectionEntries.begin();
+		     I != SectionEntries.end(); ++I) {
+			IndexTarget * Target = new IndexTarget();
+			Target->ShortDesc = "Sources";
+			Target->MetaKey = SourceIndexURISuffix(Target->ShortDesc.c_str(), (*I)->Section);
+			Target->URI = SourceIndexURI(Target->ShortDesc.c_str(), (*I)->Section);
+			Target->Description = Info (Target->ShortDesc.c_str(), (*I)->Section);
+			IndexTargets->push_back (Target);
+		}
+	}
+
+	// Only source release
+	if (IndexTargets->empty() == false && ArchEntries.size() == 1)
+		return IndexTargets;
+
+	for (map<string, vector<debSectionEntry const*> >::const_iterator a = ArchEntries.begin();
+	     a != ArchEntries.end(); ++a) {
+		if (a->first == "source")
+			continue;
+		for (vector <const debSectionEntry *>::const_iterator I = a->second.begin();
+		     I != a->second.end(); ++I) {
+			IndexTarget * Target = new IndexTarget();
+			Target->ShortDesc = "Packages";
+			Target->MetaKey = IndexURISuffix(Target->ShortDesc.c_str(), (*I)->Section, a->first);
+			Target->URI = IndexURI(Target->ShortDesc.c_str(), (*I)->Section, a->first);
+			Target->Description = Info (Target->ShortDesc.c_str(), (*I)->Section, a->first);
+			IndexTargets->push_back (Target);
+		}
+	}
+
+	return IndexTargets;
 }
 									/*}}}*/
-bool debReleaseIndex::GetIndexes(pkgAcquire *Owner, bool GetAll) const
+bool debReleaseIndex::GetIndexes(pkgAcquire *Owner, bool const &GetAll) const
 {
    // special case for --print-uris
    if (GetAll) {
@@ -170,24 +198,28 @@ bool debReleaseIndex::GetIndexes(pkgAcquire *Owner, bool GetAll) const
 		     ComputeIndexTargets(),
 		     new indexRecords (Dist));
 
-   // Queue the translations
-   std::vector<std::string> const lang = APT::Configuration::getLanguages(true);
-   for (vector<const debSectionEntry *>::const_iterator I = SectionEntries.begin(); 
-	I != SectionEntries.end(); I++) {
-
-      if((*I)->IsSrc)
-	 continue;
-
-      for (vector<string>::const_iterator l = lang.begin();
-		l != lang.end(); l++)
-      {
-	if (*l == "none") continue;
-	debTranslationsIndex i = debTranslationsIndex(URI,Dist,(*I)->Section,(*l).c_str());
-	i.GetIndexes(Owner);
-      }
-   }
-
-   return true;
+	// Queue the translations
+	std::vector<std::string> const lang = APT::Configuration::getLanguages(true);
+	map<string, set<string> > sections;
+	for (map<string, vector<debSectionEntry const*> >::const_iterator a = ArchEntries.begin();
+	     a != ArchEntries.end(); ++a) {
+		if (a->first == "source")
+			continue;
+		for (vector<debSectionEntry const*>::const_iterator I = a->second.begin();
+		     I != a->second.end(); I++)
+			sections[(*I)->Section].insert(lang.begin(), lang.end());
+	}
+
+	for (map<string, set<string> >::const_iterator s = sections.begin();
+	     s != sections.end(); ++s)
+		for (set<string>::const_iterator l = s->second.begin();
+		     l != s->second.end(); l++) {
+			if (*l == "none") continue;
+			debTranslationsIndex i = debTranslationsIndex(URI,Dist,s->first,(*l).c_str());
+			i.GetIndexes(Owner);
+		}
+
+	return true;
 }
 
 bool debReleaseIndex::IsTrusted() const
@@ -204,73 +236,113 @@ bool debReleaseIndex::IsTrusted() const
    return false;
 }
 
-vector <pkgIndexFile *> *debReleaseIndex::GetIndexFiles()
-{
-   if (Indexes != NULL)
-      return Indexes;
-
-   Indexes = new vector <pkgIndexFile*>;
-   std::vector<std::string> const lang = APT::Configuration::getLanguages(true);
-   for (vector<const debSectionEntry *>::const_iterator I = SectionEntries.begin(); 
-	I != SectionEntries.end(); I++) {
-      if ((*I)->IsSrc)
-         Indexes->push_back(new debSourcesIndex (URI, Dist, (*I)->Section, IsTrusted()));
-      else 
-      {
-         Indexes->push_back(new debPackagesIndex (URI, Dist, (*I)->Section, IsTrusted()));
-
-	 for (vector<string>::const_iterator l = lang.begin();
-		l != lang.end(); l++) {
-	    if (*l == "none") continue;
-	    Indexes->push_back(new debTranslationsIndex(URI,Dist,(*I)->Section,(*l).c_str()));
-	 }
-      }
-   }
+vector <pkgIndexFile *> *debReleaseIndex::GetIndexFiles() {
+	if (Indexes != NULL)
+		return Indexes;
+
+	Indexes = new vector <pkgIndexFile*>;
+	map<string, vector<debSectionEntry const*> >::const_iterator const src = ArchEntries.find("source");
+	if (src != ArchEntries.end()) {
+		vector<debSectionEntry const*> const SectionEntries = src->second;
+		for (vector<debSectionEntry const*>::const_iterator I = SectionEntries.begin();
+		     I != SectionEntries.end(); I++)
+			Indexes->push_back(new debSourcesIndex (URI, Dist, (*I)->Section, IsTrusted()));
+	}
+
+	// Only source release
+	if (Indexes->empty() == false && ArchEntries.size() == 1)
+		return Indexes;
+
+	std::vector<std::string> const lang = APT::Configuration::getLanguages(true);
+	map<string, set<string> > sections;
+	for (map<string, vector<debSectionEntry const*> >::const_iterator a = ArchEntries.begin();
+	     a != ArchEntries.end(); ++a) {
+		if (a->first == "source")
+			continue;
+		for (vector<debSectionEntry const*>::const_iterator I = a->second.begin();
+		     I != a->second.end(); I++) {
+			Indexes->push_back(new debPackagesIndex (URI, Dist, (*I)->Section, IsTrusted(), a->first));
+			sections[(*I)->Section].insert(lang.begin(), lang.end());
+		}
+	}
+
+	for (map<string, set<string> >::const_iterator s = sections.begin();
+	     s != sections.end(); ++s)
+		for (set<string>::const_iterator l = s->second.begin();
+		     l != s->second.end(); l++) {
+			if (*l == "none") continue;
+			Indexes->push_back(new debTranslationsIndex(URI,Dist,s->first,(*l).c_str()));
+		}
+
+	return Indexes;
+}
 
-   return Indexes;
+void debReleaseIndex::PushSectionEntry(vector<string> const &Archs, const debSectionEntry *Entry) {
+	for (vector<string>::const_iterator a = Archs.begin();
+	     a != Archs.end(); ++a)
+		ArchEntries[*a].push_back(new debSectionEntry(Entry->Section, Entry->IsSrc));
+	delete Entry;
 }
 
-void debReleaseIndex::PushSectionEntry(const debSectionEntry *Entry)
-{
-   SectionEntries.push_back(Entry);
+void debReleaseIndex::PushSectionEntry(string const &Arch, const debSectionEntry *Entry) {
+	ArchEntries[Arch].push_back(Entry);
 }
 
-debReleaseIndex::debSectionEntry::debSectionEntry (string Section, bool IsSrc): Section(Section)
-{
-   this->IsSrc = IsSrc;
+void debReleaseIndex::PushSectionEntry(const debSectionEntry *Entry) {
+	if (Entry->IsSrc == true)
+		PushSectionEntry("source", Entry);
+	else {
+		for (map<string, vector<const debSectionEntry *> >::iterator a = ArchEntries.begin();
+		     a != ArchEntries.end(); ++a) {
+			a->second.push_back(Entry);
+		}
+	}
 }
 
+debReleaseIndex::debSectionEntry::debSectionEntry (string const &Section,
+		bool const &IsSrc): Section(Section), IsSrc(IsSrc)
+{}
+
 class debSLTypeDebian : public pkgSourceList::Type
 {
    protected:
 
-   bool CreateItemInternal(vector<metaIndex *> &List,string URI,
-			   string Dist,string Section,
-			   bool IsSrc) const
+   bool CreateItemInternal(vector<metaIndex *> &List, string const &URI,
+			   string const &Dist, string const &Section,
+			   bool const &IsSrc, map<string, string> const &Options) const
    {
-      for (vector<metaIndex *>::const_iterator I = List.begin(); 
+      map<string, string>::const_iterator const arch = Options.find("arch");
+      vector<string> const Archs =
+		(arch != Options.end()) ? VectorizeString(arch->second, ',') :
+				APT::Configuration::getArchitectures();
+
+      for (vector<metaIndex *>::const_iterator I = List.begin();
 	   I != List.end(); I++)
       {
-	 // This check insures that there will be only one Release file
-	 // queued for all the Packages files and Sources files it
-	 // corresponds to.
-		if (strcmp((*I)->GetType(), "deb") == 0)
+	 // We only worry about debian entries here
+	 if (strcmp((*I)->GetType(), "deb") != 0)
+	    continue;
+
+	 debReleaseIndex *Deb = (debReleaseIndex *) (*I);
+	 /* This check insures that there will be only one Release file
+	    queued for all the Packages files and Sources files it
+	    corresponds to. */
+	 if (Deb->GetURI() == URI && Deb->GetDist() == Dist)
 	 {
-	    debReleaseIndex *Deb = (debReleaseIndex *) (*I);
-	    // This check insures that there will be only one Release file
-	    // queued for all the Packages files and Sources files it
-	    // corresponds to.
-	    if (Deb->GetURI() == URI && Deb->GetDist() == Dist)
-	    {
-	       Deb->PushSectionEntry(new debReleaseIndex::debSectionEntry(Section, IsSrc));
-	       return true;
-	    }
+	    if (IsSrc == true)
+	       Deb->PushSectionEntry("source", new debReleaseIndex::debSectionEntry(Section, IsSrc));
+	    else
+	       Deb->PushSectionEntry(Archs, new debReleaseIndex::debSectionEntry(Section, IsSrc));
+	    return true;
 	 }
       }
       // No currently created Release file indexes this entry, so we create a new one.
       // XXX determine whether this release is trusted or not
-      debReleaseIndex *Deb = new debReleaseIndex(URI,Dist);
-      Deb->PushSectionEntry (new debReleaseIndex::debSectionEntry(Section, IsSrc));
+      debReleaseIndex *Deb = new debReleaseIndex(URI, Dist);
+      if (IsSrc == true)
+	 Deb->PushSectionEntry ("source", new debReleaseIndex::debSectionEntry(Section, IsSrc));
+      else
+	 Deb->PushSectionEntry (Archs, new debReleaseIndex::debSectionEntry(Section, IsSrc));
       List.push_back(Deb);
       return true;
    }
@@ -280,10 +352,11 @@ class debSLTypeDeb : public debSLTypeDebian
 {
    public:
 
-   bool CreateItem(vector<metaIndex *> &List,string URI,
-		   string Dist,string Section) const
+   bool CreateItem(vector<metaIndex *> &List, string const &URI,
+		   string const &Dist, string const &Section,
+		   std::map<string, string> const &Options) const
    {
-      return CreateItemInternal(List, URI, Dist, Section, false);
+      return CreateItemInternal(List, URI, Dist, Section, false, Options);
    }
 
    debSLTypeDeb()
@@ -297,10 +370,11 @@ class debSLTypeDebSrc : public debSLTypeDebian
 {
    public:
 
-   bool CreateItem(vector<metaIndex *> &List,string URI,
-		   string Dist,string Section) const 
+   bool CreateItem(vector<metaIndex *> &List, string const &URI,
+		   string const &Dist, string const &Section,
+		   std::map<string, string> const &Options) const
    {
-      return CreateItemInternal(List, URI, Dist, Section, true);
+      return CreateItemInternal(List, URI, Dist, Section, true, Options);
    }
    
    debSLTypeDebSrc()

+ 16 - 12
apt-pkg/deb/debmetaindex.h

@@ -5,40 +5,44 @@
 #include <apt-pkg/metaindex.h>
 #include <apt-pkg/sourcelist.h>
 
+#include <map>
+
 class debReleaseIndex : public metaIndex {
    public:
 
    class debSectionEntry
    {
       public:
-      debSectionEntry (string Section, bool IsSrc);
-      bool IsSrc;
-      string Section;
+      debSectionEntry (string const &Section, bool const &IsSrc);
+      string const Section;
+      bool const IsSrc;
    };
 
    private:
-   vector <const debSectionEntry *> SectionEntries;
+   std::map<string, vector<debSectionEntry const*> > ArchEntries;
 
    public:
 
-   debReleaseIndex(string URI, string Dist);
+   debReleaseIndex(string const &URI, string const &Dist);
    ~debReleaseIndex();
 
-   virtual string ArchiveURI(string File) const {return URI + File;};
-   virtual bool GetIndexes(pkgAcquire *Owner, bool GetAll=false) const;
+   virtual string ArchiveURI(string const &File) const {return URI + File;};
+   virtual bool GetIndexes(pkgAcquire *Owner, bool const &GetAll=false) const;
    vector <struct IndexTarget *>* ComputeIndexTargets() const;
-   string Info(const char *Type, const string Section) const;
+   string Info(const char *Type, string const &Section, string const &Arch="") const;
    string MetaIndexInfo(const char *Type) const;
    string MetaIndexFile(const char *Types) const;
    string MetaIndexURI(const char *Type) const;
-   string IndexURI(const char *Type, const string Section) const;
-   string IndexURISuffix(const char *Type, const string Section) const;
-   string SourceIndexURI(const char *Type, const string Section) const;
-   string SourceIndexURISuffix(const char *Type, const string Section) const;
+   string IndexURI(const char *Type, string const &Section, string const &Arch="native") const;
+   string IndexURISuffix(const char *Type, string const &Section, string const &Arch="native") const;
+   string SourceIndexURI(const char *Type, const string &Section) const;
+   string SourceIndexURISuffix(const char *Type, const string &Section) const;
    virtual vector <pkgIndexFile *> *GetIndexFiles();
 
    virtual bool IsTrusted() const;
 
+   void PushSectionEntry(vector<string> const &Archs, const debSectionEntry *Entry);
+   void PushSectionEntry(string const &Arch, const debSectionEntry *Entry);
    void PushSectionEntry(const debSectionEntry *Entry);
 };
 

+ 16 - 2
apt-pkg/deb/debversion.cc

@@ -190,8 +190,22 @@ int debVersioningSystem::DoCmpVersion(const char *A,const char *AEnd,
       dlhs++;
    if (drhs != rhs)
       drhs++;
-   
-   return CmpFragment(dlhs,AEnd,drhs,BEnd);
+
+   // no debian revision need to be treated like -0
+   if (*(dlhs-1) == '-' && *(drhs-1) == '-')
+      return CmpFragment(dlhs,AEnd,drhs,BEnd);
+   else if (*(dlhs-1) == '-')
+   {
+      const char* null = "0";
+      return CmpFragment(dlhs,AEnd,null, null+1);
+   }
+   else if (*(drhs-1) == '-')
+   {
+      const char* null = "0";
+      return CmpFragment(null, null+1, drhs, BEnd);
+   }
+   else
+      return 0;
 }
 									/*}}}*/
 // debVS::CheckDep - Check a single dependency				/*{{{*/

+ 11 - 7
apt-pkg/deb/dpkgpm.cc

@@ -564,35 +564,37 @@ void pkgDPkgPM::WriteHistoryTag(string tag, string value)
 // DPkgPM::OpenLog							/*{{{*/
 bool pkgDPkgPM::OpenLog()
 {
-   string logdir = _config->FindDir("Dir::Log");
+   string const logdir = _config->FindDir("Dir::Log");
    if(not FileExists(logdir))
       return _error->Error(_("Directory '%s' missing"), logdir.c_str());
 
    // get current time
    char timestr[200];
-   time_t t = time(NULL);
-   struct tm *tmp = localtime(&t);
+   time_t const t = time(NULL);
+   struct tm const * const tmp = localtime(&t);
    strftime(timestr, sizeof(timestr), "%F  %T", tmp);
 
    // open terminal log
-   string logfile_name = flCombine(logdir,
+   string const logfile_name = flCombine(logdir,
 				   _config->Find("Dir::Log::Terminal"));
    if (!logfile_name.empty())
    {
       term_out = fopen(logfile_name.c_str(),"a");
       if (term_out == NULL)
-	 return _error->WarningE(_("Could not open file '%s'"), logfile_name.c_str());
+	 return _error->WarningE("OpenLog", _("Could not open file '%s'"), logfile_name.c_str());
 
       chmod(logfile_name.c_str(), 0600);
       fprintf(term_out, "\nLog started: %s\n", timestr);
    }
 
-   // write 
-   string history_name = flCombine(logdir,
+   // write your history
+   string const history_name = flCombine(logdir,
 				   _config->Find("Dir::Log::History"));
    if (!history_name.empty())
    {
       history_out = fopen(history_name.c_str(),"a");
+      if (history_out == NULL)
+	 return _error->WarningE("OpenLog", _("Could not open file '%s'"), history_name.c_str());
       chmod(history_name.c_str(), 0644);
       fprintf(history_out, "\nStart-Date: %s\n", timestr);
       string remove, purge, install, upgrade, downgrade;
@@ -612,6 +614,8 @@ bool pkgDPkgPM::OpenLog()
 	       remove += I.Name() + string(" (") + Cache[I].CurVersion + string("), ");	    
 	 }
       }
+      if (_config->Exists("Commandline::AsString") == true)
+	 WriteHistoryTag("Commandline", _config->Find("Commandline::AsString"));
       WriteHistoryTag("Install", install);
       WriteHistoryTag("Upgrade", upgrade);
       WriteHistoryTag("Downgrade",downgrade);

+ 330 - 69
apt-pkg/depcache.cc

@@ -17,6 +17,7 @@
 #include <apt-pkg/fileutl.h>
 #include <apt-pkg/strutl.h>
 #include <apt-pkg/configuration.h>
+#include <apt-pkg/aptconfiguration.h>
 #include <apt-pkg/pkgsystem.h>
 #include <apt-pkg/tagfile.h>
 
@@ -164,34 +165,46 @@ bool pkgDepCache::Init(OpProgress *Prog)
 bool pkgDepCache::readStateFile(OpProgress *Prog)			/*{{{*/
 {
    FileFd state_file;
-   string state = _config->FindDir("Dir::State") + "extended_states";
+   string const state = _config->FindDir("Dir::State") + "extended_states";
    if(FileExists(state)) {
       state_file.Open(state, FileFd::ReadOnly);
-      int file_size = state_file.Size();
+      int const file_size = state_file.Size();
       if(Prog != NULL)
 	 Prog->OverallProgress(0, file_size, 1, 
 			       _("Reading state information"));
 
       pkgTagFile tagfile(&state_file);
       pkgTagSection section;
-      int amt=0;
-      bool debug_autoremove=_config->FindB("Debug::pkgAutoRemove",false);
+      int amt = 0;
+      bool const debug_autoremove = _config->FindB("Debug::pkgAutoRemove",false);
       while(tagfile.Step(section)) {
-	 string pkgname = section.FindS("Package");
-	 pkgCache::PkgIterator pkg=Cache->FindPkg(pkgname);
-	 // Silently ignore unknown packages and packages with no actual
-	 // version.
-	 if(!pkg.end() && !pkg.VersionList().end()) {
-	    short reason = section.FindI("Auto-Installed", 0);
-	    if(reason > 0)
-	       PkgState[pkg->ID].Flags  |= Flag::Auto;
-	    if(debug_autoremove)
-	       std::cout << "Auto-Installed : " << pkgname << std::endl;
-	    amt+=section.size();
-	    if(Prog != NULL)
-	       Prog->OverallProgress(amt, file_size, 1, 
-				     _("Reading state information"));
+	 string const pkgname = section.FindS("Package");
+	 string pkgarch = section.FindS("Architecture");
+	 if (pkgarch.empty() == true)
+	    pkgarch = "any";
+	 pkgCache::PkgIterator pkg = Cache->FindPkg(pkgname, pkgarch);
+	 // Silently ignore unknown packages and packages with no actual version.
+	 if(pkg.end() == true || pkg->VersionList == 0)
+	    continue;
+
+	 short const reason = section.FindI("Auto-Installed", 0);
+	 if(reason > 0)
+	 {
+	    PkgState[pkg->ID].Flags |= Flag::Auto;
+	    if (unlikely(debug_autoremove))
+	       std::cout << "Auto-Installed : " << pkg.FullName() << std::endl;
+	    if (pkgarch == "any")
+	    {
+	       pkgCache::GrpIterator G = pkg.Group();
+	       for (pkg = G.NextPkg(pkg); pkg.end() != true; pkg = G.NextPkg(pkg))
+		  if (pkg->VersionList != 0)
+		     PkgState[pkg->ID].Flags |= Flag::Auto;
+	    }
 	 }
+	 amt += section.size();
+	 if(Prog != NULL)
+	    Prog->OverallProgress(amt, file_size, 1, 
+				  _("Reading state information"));
       }
       if(Prog != NULL)
 	 Prog->OverallProgress(file_size, file_size, 1,
@@ -203,13 +216,13 @@ bool pkgDepCache::readStateFile(OpProgress *Prog)			/*{{{*/
 									/*}}}*/
 bool pkgDepCache::writeStateFile(OpProgress *prog, bool InstalledOnly)	/*{{{*/
 {
-   bool debug_autoremove = _config->FindB("Debug::pkgAutoRemove",false);
+   bool const debug_autoremove = _config->FindB("Debug::pkgAutoRemove",false);
    
    if(debug_autoremove)
       std::clog << "pkgDepCache::writeStateFile()" << std::endl;
 
    FileFd StateFile;
-   string state = _config->FindDir("Dir::State") + "extended_states";
+   string const state = _config->FindDir("Dir::State") + "extended_states";
 
    // if it does not exist, create a empty one
    if(!FileExists(state)) 
@@ -224,7 +237,7 @@ bool pkgDepCache::writeStateFile(OpProgress *prog, bool InstalledOnly)	/*{{{*/
 			   state.c_str());
 
    FILE *OutFile;
-   string outfile = state + ".tmp";
+   string const outfile = state + ".tmp";
    if((OutFile = fopen(outfile.c_str(),"w")) == NULL)
       return _error->Error(_("Failed to write temporary StateFile %s"),
 			   outfile.c_str());
@@ -235,46 +248,72 @@ bool pkgDepCache::writeStateFile(OpProgress *prog, bool InstalledOnly)	/*{{{*/
    std::set<string> pkgs_seen;
    const char *nullreorderlist[] = {0};
    while(tagfile.Step(section)) {
-	 string pkgname = section.FindS("Package");
+	 string const pkgname = section.FindS("Package");
+	 string pkgarch = section.FindS("Architecture");
+	 if (pkgarch.empty() == true)
+	    pkgarch = "native";
 	 // Silently ignore unknown packages and packages with no actual
 	 // version.
-	 pkgCache::PkgIterator pkg=Cache->FindPkg(pkgname);
+	 pkgCache::PkgIterator pkg = Cache->FindPkg(pkgname, pkgarch);
 	 if(pkg.end() || pkg.VersionList().end()) 
 	    continue;
-	 bool newAuto = (PkgState[pkg->ID].Flags & Flag::Auto);
+	 StateCache const &P = PkgState[pkg->ID];
+	 bool newAuto = (P.Flags & Flag::Auto);
+	 // skip not installed or now-removed ones if requested
+	 if (InstalledOnly && (
+	     (pkg->CurrentVer == 0 && P.Mode != ModeInstall) ||
+	     (pkg->CurrentVer != 0 && P.Mode == ModeDelete)))
+	 {
+	    // The section is obsolete if it contains no other tag
+	    unsigned int const count = section.Count();
+	    if (count < 2 ||
+		(count == 2 && section.Exists("Auto-Installed")) ||
+		(count == 3 && section.Exists("Auto-Installed") && section.Exists("Architecture")))
+	       continue;
+	    else
+	       newAuto = false;
+	 }
 	 if(_config->FindB("Debug::pkgAutoRemove",false))
 	    std::clog << "Update existing AutoInstall info: " 
-		      << pkg.Name() << std::endl;
-	 TFRewriteData rewrite[2];
-	 rewrite[0].Tag = "Auto-Installed";
-	 rewrite[0].Rewrite = newAuto ? "1" : "0";
+		      << pkg.FullName() << std::endl;
+	 TFRewriteData rewrite[3];
+	 rewrite[0].Tag = "Architecture";
+	 rewrite[0].Rewrite = pkg.Arch();
 	 rewrite[0].NewTag = 0;
-	 rewrite[1].Tag = 0;
+	 rewrite[1].Tag = "Auto-Installed";
+	 rewrite[1].Rewrite = newAuto ? "1" : "0";
+	 rewrite[1].NewTag = 0;
+	 rewrite[2].Tag = 0;
 	 TFRewrite(OutFile, section, nullreorderlist, rewrite);
 	 fprintf(OutFile,"\n");
-	 pkgs_seen.insert(pkgname);
+	 pkgs_seen.insert(pkg.FullName());
    }
    
    // then write the ones we have not seen yet
    std::ostringstream ostr;
    for(pkgCache::PkgIterator pkg=Cache->PkgBegin(); !pkg.end(); pkg++) {
-      if(PkgState[pkg->ID].Flags & Flag::Auto) {
-	 if (pkgs_seen.find(pkg.Name()) != pkgs_seen.end()) {
+      StateCache const &P = PkgState[pkg->ID];
+      if(P.Flags & Flag::Auto) {
+	 if (pkgs_seen.find(pkg.FullName()) != pkgs_seen.end()) {
 	    if(debug_autoremove)
-	       std::clog << "Skipping already written " << pkg.Name() << std::endl;
+	       std::clog << "Skipping already written " << pkg.FullName() << std::endl;
 	    continue;
 	 }
-         // skip not installed ones if requested
-         if(InstalledOnly && pkg->CurrentVer == 0)
-            continue;
+	 // skip not installed ones if requested
+	 if (InstalledOnly && (
+	     (pkg->CurrentVer == 0 && P.Mode != ModeInstall) ||
+	     (pkg->CurrentVer != 0 && P.Mode == ModeDelete)))
+	    continue;
+	 const char* const pkgarch = pkg.Arch();
+	 if (strcmp(pkgarch, "all") == 0)
+	    continue;
 	 if(debug_autoremove)
-	    std::clog << "Writing new AutoInstall: " 
-		      << pkg.Name() << std::endl;
+	    std::clog << "Writing new AutoInstall: " << pkg.FullName() << std::endl;
 	 ostr.str(string(""));
-	 ostr << "Package: " << pkg.Name() 
+	 ostr << "Package: " << pkg.Name()
+	      << "\nArchitecture: " << pkgarch
 	      << "\nAuto-Installed: 1\n\n";
 	 fprintf(OutFile,"%s",ostr.str().c_str());
-	 fprintf(OutFile,"\n");
       }
    }
    fclose(OutFile);
@@ -596,6 +635,107 @@ void pkgDepCache::UpdateVerState(PkgIterator Pkg)
    }
 }
 									/*}}}*/
+// DepCache::RemovePseudoInstalledPkg - MultiArch helper for Update()	/*{{{*/
+// ---------------------------------------------------------------------
+/* We "install" arch all packages for all archs if it is installed. Many
+   of these will be broken. This method will look at these broken Pkg and
+   "remove" it. */
+bool pkgDepCache::RemovePseudoInstalledPkg(PkgIterator &Pkg, std::set<unsigned long> &recheck) {
+   if (unlikely(Pkg->CurrentVer == 0))
+      return false;
+
+   VerIterator V = Pkg.CurrentVer();
+   if (V->MultiArch != Version::All)
+      return false;
+
+   // Never ever kill an "all" package - they have no dependency so they can't be broken
+   if (strcmp(Pkg.Arch(),"all") == 0)
+      return false;
+
+   unsigned char const CurDepState = VersionState(V.DependsList(),DepInstall,DepInstMin,DepInstPolicy);
+   if ((CurDepState & DepInstMin) == DepInstMin) {
+      // okay, the package isn't broken, but is the package also required?
+      // If it has no real dependencies, no installed rdepends and doesn't
+      // provide something of value, we will kill it as not required.
+      // These pseudopackages have otherwise interesting effects if they get
+      // a new dependency in a newer version…
+      for (pkgCache::DepIterator D = V.DependsList();
+	   D.end() != true; ++D)
+	 if (D.IsCritical() == true && D.ParentPkg()->Group != Pkg->Group)
+	    return false;
+      for (DepIterator D = Pkg.RevDependsList(); D.end() != true; ++D)
+      {
+	 if (D.IsCritical() == false)
+	    continue;
+	 PkgIterator const P = D.ParentPkg();
+	 if (P->Group == Pkg->Group)
+	    continue;
+	 if (P->CurrentVer != 0)
+	    return false;
+      }
+      for (PrvIterator Prv = V.ProvidesList(); Prv.end() != true; Prv++)
+	 for (DepIterator d = Prv.ParentPkg().RevDependsList();
+	      d.end() != true; ++d)
+	 {
+	    PkgIterator const P = d.ParentPkg();
+	    if (P->CurrentVer != 0 &&
+	        P->Group != Pkg->Group)
+	       return false;
+	 }
+   }
+
+   // Dependencies for this arch all package are not statisfied
+   // so we installed it only for our convenience: get right of it now.
+   RemoveSizes(Pkg);
+   RemoveStates(Pkg);
+
+   Pkg->CurrentVer = 0;
+   PkgState[Pkg->ID].InstallVer = 0;
+
+   AddStates(Pkg);
+   Update(Pkg);
+   AddSizes(Pkg);
+
+   // After the remove previously satisfied pseudo pkg could be now
+   // no longer satisfied, so we need to recheck the reverse dependencies
+   for (DepIterator d = Pkg.RevDependsList(); d.end() != true; ++d)
+   {
+      PkgIterator const P = d.ParentPkg();
+      if (P->CurrentVer != 0)
+	 recheck.insert(P.Index());
+   }
+
+   for (DepIterator d = V.DependsList(); d.end() != true; ++d)
+   {
+      PkgIterator const P = d.TargetPkg();
+      for (PrvIterator Prv = P.ProvidesList(); Prv.end() != true; ++Prv)
+      {
+	 PkgIterator const O = Prv.OwnerPkg();
+	 if (O->CurrentVer != 0)
+	    recheck.insert(O.Index());
+      }
+
+      if (P->CurrentVer != 0)
+	 recheck.insert(P.Index());
+   }
+
+   for (PrvIterator Prv = V.ProvidesList(); Prv.end() != true; Prv++)
+   {
+      for (DepIterator d = Prv.ParentPkg().RevDependsList();
+	   d.end() != true; ++d)
+      {
+	 PkgIterator const P = d.ParentPkg();
+	 if (P->CurrentVer == 0)
+	    continue;
+
+	    recheck.insert(P.Index());
+      }
+   }
+
+
+   return true;
+}
+									/*}}}*/
 // DepCache::Update - Figure out all the state information		/*{{{*/
 // ---------------------------------------------------------------------
 /* This will figure out the state of all the packages and all the 
@@ -609,9 +749,13 @@ void pkgDepCache::Update(OpProgress *Prog)
    iKeepCount = 0;
    iBrokenCount = 0;
    iBadCount = 0;
-   
+
+   std::set<unsigned long> recheck;
+
    // Perform the depends pass
    int Done = 0;
+   bool const checkMultiArch = APT::Configuration::getArchitectures().size() > 1;
+   unsigned long killed = 0;
    for (PkgIterator I = PkgBegin(); I.end() != true; I++,Done++)
    {
       if (Prog != 0 && Done%20 == 0)
@@ -619,7 +763,7 @@ void pkgDepCache::Update(OpProgress *Prog)
       for (VerIterator V = I.VersionList(); V.end() != true; V++)
       {
 	 unsigned char Group = 0;
-	 
+
 	 for (DepIterator D = V.DependsList(); D.end() != true; D++)
 	 {
 	    // Build the dependency state.
@@ -637,16 +781,105 @@ void pkgDepCache::Update(OpProgress *Prog)
 		D->Type == Dep::DpkgBreaks ||
 		D->Type == Dep::Obsoletes)
 	       State = ~State;
-	 }	 
+	 }
       }
 
-      // Compute the pacakge dependency state and size additions
+      // Compute the package dependency state and size additions
       AddSizes(I);
       UpdateVerState(I);
       AddStates(I);
+
+      if (checkMultiArch != true || I->CurrentVer == 0)
+	 continue;
+
+      VerIterator const V = I.CurrentVer();
+      if (V->MultiArch != Version::All)
+	 continue;
+
+      recheck.insert(I.Index());
+      --Done; // no progress if we need to recheck the package
    }
 
-   if (Prog != 0)      
+   if (checkMultiArch == true) {
+      /* FIXME: recheck breaks proper progress reporting as we don't know
+		how many packages we need to recheck. To lower the effect
+		a bit we increase with a kill, but we should do something more clever… */
+      for(std::set<unsigned long>::const_iterator p = recheck.begin();
+	  p != recheck.end(); ++p) {
+	 if (Prog != 0 && Done%20 == 0)
+	    Prog->Progress(Done);
+	 PkgIterator P = PkgIterator(*Cache, Cache->PkgP + *p);
+	 if (RemovePseudoInstalledPkg(P, recheck) == true) {
+	    ++killed;
+	    ++Done;
+	 }
+	 recheck.erase(p);
+      }
+
+      /* Okay, we have killed a great amount of pseudopackages -
+	 we have killed so many that we have now arch "all" packages
+	 without an installed pseudo package, but we NEED an installed
+	 pseudo package, so we will search now for a pseudo package
+	 we can install without breaking everything. */
+      for (GrpIterator G = Cache->GrpBegin(); G.end() != true; ++G)
+      {
+	 PkgIterator P = G.FindPkg("all");
+	 if (P.end() == true)
+	    continue;
+	 if (P->CurrentVer == 0)
+	    continue;
+	 bool installed = false;
+	 for (P = G.FindPkg("any"); P.end() != true; P = G.NextPkg(P))
+	 {
+	    if (strcmp(P.Arch(), "all") == 0)
+	       continue;
+	    if (P->CurrentVer == 0)
+	       continue;
+	    installed = true;
+	    break;
+	 }
+	 if (installed == false)
+	    recheck.insert(G.Index());
+      }
+      std::vector<std::string> Archs = APT::Configuration::getArchitectures();
+      bool checkChanged = false;
+      do {
+	 for(std::set<unsigned long>::const_iterator g = recheck.begin();
+	     g != recheck.end(); ++g) {
+	    GrpIterator G = GrpIterator(*Cache, Cache->GrpP + *g);
+	    VerIterator allV = G.FindPkg("all").CurrentVer();
+	    for (std::vector<std::string>::const_iterator a = Archs.begin();
+		 a != Archs.end(); ++a)
+	    {
+	       PkgIterator P = G.FindPkg(*a);
+	       if (P.end() == true) continue;
+	       for (VerIterator V = P.VersionList(); V.end() != true; ++V)
+	       {
+		  // FIXME: String comparison isn't a save indicator!
+		  if (strcmp(allV.VerStr(),V.VerStr()) != 0)
+		     continue;
+		  unsigned char const CurDepState = VersionState(V.DependsList(),DepInstall,DepInstMin,DepInstPolicy);
+		  if ((CurDepState & DepInstMin) != DepInstMin)
+		     break; // we found the correct version, but it is broken. Better try another arch or later again
+		  P->CurrentVer = V.Index();
+		  AddStates(P);
+		  Update(P);
+		  AddSizes(P);
+		  checkChanged = true;
+		  break;
+	       }
+	    }
+	    recheck.erase(g);
+	 }
+      } while (checkChanged == true && recheck.empty() == false);
+
+      if (_config->FindB("Debug::MultiArchKiller", false) == true)
+	 for(std::set<unsigned long>::const_iterator g = recheck.begin();
+	     g != recheck.end(); ++g)
+	    std::cout << "No pseudo package for »" << GrpIterator(*Cache, Cache->GrpP + *g).Name() << "« installed" << std::endl;
+   }
+
+   if (Prog != 0)
       Prog->Progress(Done);
 
    readStateFile(Prog);
@@ -813,6 +1046,10 @@ void pkgDepCache::MarkDelete(PkgIterator const &Pkg, bool rPurge,
    AddStates(Pkg);   
    Update(Pkg);
    AddSizes(Pkg);
+
+   // if we remove the pseudo package, we also need to remove the "real"
+   if (Pkg->CurrentVer != 0 && Pkg.CurrentVer().Pseudo() == true)
+      MarkDelete(Pkg.Group().FindPkg("all"), rPurge, Depth+1, FromUser);
 }
 									/*}}}*/
 // DepCache::IsDeleteOk - check if it is ok to remove this package	/*{{{*/
@@ -1339,7 +1576,7 @@ bool pkgDepCache::MarkRequired(InRootSetFunc &userFunc)
 
       // debug output
       if(debug_autoremove && PkgState[p->ID].Flags & Flag::Auto)
-  	 std::clog << "AutoDep: " << p.Name() << std::endl;
+  	 std::clog << "AutoDep: " << p.FullName() << std::endl;
    }
 
    // init vars
@@ -1373,13 +1610,18 @@ bool pkgDepCache::MarkRequired(InRootSetFunc &userFunc)
 // MarkPackage - mark a single package in Mark-and-Sweep		/*{{{*/
 void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
 			      const pkgCache::VerIterator &ver,
-			      bool follow_recommends,
-			      bool follow_suggests)
+			      bool const &follow_recommends,
+			      bool const &follow_suggests)
 {
    pkgDepCache::StateCache &state = PkgState[pkg->ID];
-   VerIterator currver            = pkg.CurrentVer();
-   VerIterator candver            = state.CandidateVerIter(*this);
-   VerIterator instver            = state.InstVerIter(*this);
+
+   // if we are marked already we are done
+   if(state.Marked)
+      return;
+
+   VerIterator const currver = pkg.CurrentVer();
+   VerIterator const candver = state.CandidateVerIter(*this);
+   VerIterator const instver = state.InstVerIter(*this);
 
 #if 0
    // If a package was garbage-collected but is now being marked, we
@@ -1405,15 +1647,11 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
       !(ver == currver && instver.end() && !ver.end()))
       return;
 
-   // if we are marked already we are done
-   if(state.Marked)
-      return;
+   bool const debug_autoremove = _config->FindB("Debug::pkgAutoRemove", false);
 
-   bool debug_autoremove = _config->FindB("Debug::pkgAutoRemove", false);
-   
    if(debug_autoremove)
      {
-       std::clog << "Marking: " << pkg.Name();
+       std::clog << "Marking: " << pkg.FullName();
        if(!ver.end())
 	 std::clog << " " << ver.VerStr();
        if(!currver.end())
@@ -1425,8 +1663,34 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
 
    state.Marked=true;
 
-   if(!ver.end())
+   if(ver.end() == true)
+      return;
+
+   // If the version belongs to a Multi-Arch all package
+   // we will mark all others in this Group with this version also
+   // Beware: We compare versions here the lazy way: string comparision
+   // this is bad if multiple repositories provide different versions
+   // of the package with an identical version number - but even in this
+   // case the dependencies are likely the same.
+   if (ver->MultiArch == pkgCache::Version::All &&
+	strcmp(ver.Arch(true), "all") == 0)
    {
+      GrpIterator G = pkg.Group();
+      const char* const VerStr = ver.VerStr();
+      for (PkgIterator P = G.FindPkg("any");
+	   P.end() != true; P = G.NextPkg(P))
+      {
+	 for (VerIterator V = P.VersionList();
+	      V.end() != true; ++V)
+	 {
+	    if (strcmp(VerStr, V.VerStr()) != 0)
+	       continue;
+	    MarkPackage(P, V, follow_recommends, follow_suggests);
+	    break;
+	 }
+      }
+   }
+
      for(DepIterator d = ver.DependsList(); !d.end(); ++d)
      {
 	if(d->Type == Dep::Depends ||
@@ -1444,10 +1708,9 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
 	      {
 		if(debug_autoremove)
 		  {
-		    std::clog << "Following dep: " << d.ParentPkg().Name()
+		    std::clog << "Following dep: " << d.ParentPkg().FullName()
 			      << " " << d.ParentVer().VerStr() << " "
-			      << d.DepType() << " "
-			      << d.TargetPkg().Name();
+			      << d.DepType() << " " << d.TargetPkg().FullName();
 		    if((d->CompareOp & ~pkgCache::Dep::Or) != pkgCache::Dep::NoOp)
 		      {
 			std::clog << " (" << d.CompType() << " "
@@ -1455,7 +1718,7 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
 		      }
 		    std::clog << std::endl;
 		  }
-		 MarkPackage(V.ParentPkg(), V, 
+		 MarkPackage(V.ParentPkg(), V,
 			     follow_recommends, follow_suggests);
 	      }
 	   }
@@ -1468,17 +1731,16 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
 	      {
 		if(debug_autoremove)
 		  {
-		    std::clog << "Following dep: " << d.ParentPkg().Name()
-			      << " " << d.ParentVer().VerStr() << " "
-			      << d.DepType() << " "
-			      << d.TargetPkg().Name();
+		    std::clog << "Following dep: " << d.ParentPkg().FullName() << " "
+			      << d.ParentVer().VerStr() << " "
+			      << d.DepType() << " " << d.TargetPkg().FullName() << " ";
 		    if((d->CompareOp & ~pkgCache::Dep::Or) != pkgCache::Dep::NoOp)
 		      {
 			std::clog << " (" << d.CompType() << " "
 				  << d.TargetVer() << ")";
 		      }
 		    std::clog << ", provided by "
-			      << prv.OwnerPkg().Name() << " "
+			      << prv.OwnerPkg().FullName() << " "
 			      << prv.OwnerVer().VerStr()
 			      << std::endl;
 		  }
@@ -1489,7 +1751,6 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
 	   }
 	}
      }
-   }
 }
 									/*}}}*/
 bool pkgDepCache::Sweep()						/*{{{*/
@@ -1511,7 +1772,7 @@ bool pkgDepCache::Sweep()						/*{{{*/
      {
 	state.Garbage=true;
 	if(debug_autoremove)
-	   std::cout << "Garbage: " << p.Name() << std::endl;
+	   std::cout << "Garbage: " << p.FullName() << std::endl;
      }
   }   
 

+ 13 - 7
apt-pkg/depcache.h

@@ -46,6 +46,7 @@
 
 #include <vector>
 #include <memory>
+#include <set>
 
 class pkgDepCache : protected pkgCache::Namespace
 {
@@ -78,8 +79,8 @@ class pkgDepCache : protected pkgCache::Namespace
     */
    void MarkPackage(const pkgCache::PkgIterator &pkg,
 		    const pkgCache::VerIterator &ver,
-		    bool follow_recommends,
-		    bool follow_suggests);
+		    bool const &follow_recommends,
+		    bool const &follow_suggests);
 
    /** \brief Update the Marked field of all packages.
     *
@@ -331,7 +332,9 @@ class pkgDepCache : protected pkgCache::Namespace
    inline operator pkgCache &() {return *Cache;};
    inline Header &Head() {return *Cache->HeaderP;};
    inline PkgIterator PkgBegin() {return Cache->PkgBegin();};
+   inline GrpIterator FindGrp(string const &Name) {return Cache->FindGrp(Name);};
    inline PkgIterator FindPkg(string const &Name) {return Cache->FindPkg(Name);};
+   inline PkgIterator FindPkg(string const &Name, string const &Arch) {return Cache->FindPkg(Name, Arch);};
 
    inline pkgCache &GetCache() {return *Cache;};
    inline pkgVersioningSystem &VS() {return *Cache->VS;};
@@ -442,12 +445,9 @@ class pkgDepCache : protected pkgCache::Namespace
    virtual bool IsDeleteOk(const PkgIterator &Pkg,bool Purge = false,
 			    unsigned long Depth = 0, bool FromUser = true);
 
-   // This is for debuging
-   void Update(OpProgress *Prog = 0);
-
    // read persistent states
    bool readStateFile(OpProgress *prog);
-   bool writeStateFile(OpProgress *prog, bool InstalledOnly=false);
+   bool writeStateFile(OpProgress *prog, bool InstalledOnly=true);
    
    // Size queries
    inline double UsrSize() {return iUsrSize;};
@@ -460,9 +460,15 @@ class pkgDepCache : protected pkgCache::Namespace
    inline unsigned long BadCount() {return iBadCount;};
 
    bool Init(OpProgress *Prog);
-   
+   // Generate all state information
+   void Update(OpProgress *Prog = 0);
+
    pkgDepCache(pkgCache *Cache,Policy *Plcy = 0);
    virtual ~pkgDepCache();
+
+   private:
+   // Helper for Update(OpProgress) to remove pseudoinstalled arch all packages
+   bool RemovePseudoInstalledPkg(PkgIterator &Pkg, std::set<unsigned long> &recheck);
 };
 
 #endif

+ 2 - 2
apt-pkg/metaindex.h

@@ -33,8 +33,8 @@ class metaIndex
    virtual const char* GetType() const {return Type;}
 
    // Interface for acquire
-   virtual string ArchiveURI(string /*File*/) const = 0;
-   virtual bool GetIndexes(pkgAcquire *Owner, bool GetAll=false) const = 0;
+   virtual string ArchiveURI(string const& /*File*/) const = 0;
+   virtual bool GetIndexes(pkgAcquire *Owner, bool const &GetAll=false) const = 0;
    
    virtual vector<pkgIndexFile *> *GetIndexFiles() = 0; 
    virtual bool IsTrusted() const = 0;

+ 9 - 4
apt-pkg/orderlist.cc

@@ -126,6 +126,11 @@ bool pkgOrderList::IsMissing(PkgIterator Pkg)
    
    if (FileList[Pkg->ID].empty() == false)
       return false;
+
+   // Missing Pseudo packages are missing if the real package is missing
+   if (pkgCache::VerIterator(Cache, Cache[Pkg].CandidateVer).Pseudo() == true)
+      return IsMissing(Pkg.Group().FindPkg("all"));
+
    return true;
 }
 									/*}}}*/
@@ -199,7 +204,7 @@ bool pkgOrderList::OrderCritical()
       {
 	 PkgIterator P(Cache,*I);
 	 if (IsNow(P) == true)
-	    clog << "  " << P.Name() << ' ' << IsMissing(P) << ',' << IsFlag(P,After) << endl;
+	    clog << "  " << P.FullName() << ' ' << IsMissing(P) << ',' << IsFlag(P,After) << endl;
       }
    }
 
@@ -272,7 +277,7 @@ bool pkgOrderList::OrderUnpack(string *FileList)
       {
 	 PkgIterator P(Cache,*I);
 	 if (IsNow(P) == true)
-	    clog << "  " << P.Name() << ' ' << IsMissing(P) << ',' << IsFlag(P,After) << endl;
+	    clog << "  " << P.FullName() << ' ' << IsMissing(P) << ',' << IsFlag(P,After) << endl;
       }
    }
 
@@ -543,7 +548,7 @@ bool pkgOrderList::VisitNode(PkgIterator Pkg)
    if (Debug == true)
    {
       for (int j = 0; j != Depth; j++) clog << ' ';
-      clog << "Visit " << Pkg.Name() << endl;
+      clog << "Visit " << Pkg.FullName() << endl;
    }
    
    Depth++;
@@ -602,7 +607,7 @@ bool pkgOrderList::VisitNode(PkgIterator Pkg)
    if (Debug == true)
    {
       for (int j = 0; j != Depth; j++) clog << ' ';
-      clog << "Leave " << Pkg.Name() << ' ' << IsFlag(Pkg,Added) << ',' << IsFlag(Pkg,AddPending) << endl;
+      clog << "Leave " << Pkg.FullName() << ' ' << IsFlag(Pkg,Added) << ',' << IsFlag(Pkg,AddPending) << endl;
    }
    
    return true;

+ 24 - 8
apt-pkg/packagemanager.cc

@@ -80,7 +80,10 @@ bool pkgPackageManager::GetArchives(pkgAcquire *Owner,pkgSourceList *Sources,
       // Skip already processed packages
       if (List->IsNow(Pkg) == false)
 	 continue;
-	 
+
+      if (pkgCache::VerIterator(Cache, Cache[Pkg].CandidateVer).Pseudo() == true)
+	 continue;
+
       new pkgAcqArchive(Owner,Sources,Recs,Cache[Pkg].InstVerIter(Cache),
 			FileNames[Pkg->ID]);
    }
@@ -277,8 +280,10 @@ bool pkgPackageManager::ConfigureAll()
    for (pkgOrderList::iterator I = OList.begin(); I != OList.end(); I++)
    {
       PkgIterator Pkg(Cache,*I);
-      
-      if (ConfigurePkgs == true && Configure(Pkg) == false)
+
+      if (ConfigurePkgs == true &&
+	  pkgCache::VerIterator(Cache, Cache[Pkg].CandidateVer).Pseudo() == false &&
+	  Configure(Pkg) == false)
 	 return false;
       
       List->Flag(Pkg,pkgOrderList::Configured,pkgOrderList::States);
@@ -313,7 +318,9 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg)
    {
       PkgIterator Pkg(Cache,*I);
       
-      if (ConfigurePkgs == true && Configure(Pkg) == false)
+      if (ConfigurePkgs == true &&
+	  pkgCache::VerIterator(Cache, Cache[Pkg].CandidateVer).Pseudo() == false &&
+	  Configure(Pkg) == false)
 	 return false;
       
       List->Flag(Pkg,pkgOrderList::Configured,pkgOrderList::States);
@@ -465,7 +472,12 @@ bool pkgPackageManager::SmartRemove(PkgIterator Pkg)
       return true;
 
    List->Flag(Pkg,pkgOrderList::Configured,pkgOrderList::States);
-   return Remove(Pkg,(Cache[Pkg].iFlags & pkgDepCache::Purge) == pkgDepCache::Purge);
+
+   if (pkgCache::VerIterator(Cache, Cache[Pkg].CandidateVer).Pseudo() == false)
+      return Remove(Pkg,(Cache[Pkg].iFlags & pkgDepCache::Purge) == pkgDepCache::Purge);
+   else
+      return SmartRemove(Pkg.Group().FindPkg("all"));
+   return true;
 }
 									/*}}}*/
 // PM::SmartUnPack - Install helper					/*{{{*/
@@ -579,10 +591,14 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg)
    for (PrvIterator P = Cache[Pkg].InstVerIter(Cache).ProvidesList(); 
 	P.end() == false; P++)
       CheckRConflicts(Pkg,P.ParentPkg().RevDependsList(),P.ProvideVersion());
-   
-   if (Install(Pkg,FileNames[Pkg->ID]) == false)
+
+   if (pkgCache::VerIterator(Cache, Cache[Pkg].CandidateVer).Pseudo() == false)
+   {
+      if(Install(Pkg,FileNames[Pkg->ID]) == false)
+         return false;
+   } else if (SmartUnPack(Pkg.Group().FindPkg("all")) == false)
       return false;
-   
+
    List->Flag(Pkg,pkgOrderList::UnPacked,pkgOrderList::States);
    
    // Perform immedate configuration of the package.

+ 199 - 41
apt-pkg/pkgcache.cc

@@ -79,7 +79,8 @@ pkgCache::Header::Header()
    StringList = 0;
    VerSysName = 0;
    Architecture = 0;
-   memset(HashTable,0,sizeof(HashTable));
+   memset(PkgHashTable,0,sizeof(PkgHashTable));
+   memset(GrpHashTable,0,sizeof(GrpHashTable));
    memset(Pools,0,sizeof(Pools));
 }
 									/*}}}*/
@@ -107,6 +108,7 @@ bool pkgCache::Header::CheckSizes(Header &Against) const
 /* */
 pkgCache::pkgCache(MMap *Map, bool DoMap) : Map(*Map)
 {
+   MultiArchEnabled = APT::Configuration::getArchitectures().size() > 1;
    if (DoMap == true)
       ReMap();
 }
@@ -118,6 +120,7 @@ bool pkgCache::ReMap()
 {
    // Apply the typecasts.
    HeaderP = (Header *)Map.Data();
+   GrpP = (Group *)Map.Data();
    PkgP = (Package *)Map.Data();
    VerFileP = (VerFile *)Map.Data();
    DescFileP = (DescFile *)Map.Data();
@@ -165,7 +168,7 @@ unsigned long pkgCache::sHash(const string &Str) const
    unsigned long Hash = 0;
    for (string::const_iterator I = Str.begin(); I != Str.end(); I++)
       Hash = 5*Hash + tolower_ascii(*I);
-   return Hash % _count(HeaderP->HashTable);
+   return Hash % _count(HeaderP->PkgHashTable);
 }
 
 unsigned long pkgCache::sHash(const char *Str) const
@@ -173,26 +176,82 @@ unsigned long pkgCache::sHash(const char *Str) const
    unsigned long Hash = 0;
    for (const char *I = Str; *I != 0; I++)
       Hash = 5*Hash + tolower_ascii(*I);
-   return Hash % _count(HeaderP->HashTable);
+   return Hash % _count(HeaderP->PkgHashTable);
 }
 
 									/*}}}*/
-// Cache::FindPkg - Locate a package by name				/*{{{*/
+// Cache::SingleArchFindPkg - Locate a package by name			/*{{{*/
 // ---------------------------------------------------------------------
-/* Returns 0 on error, pointer to the package otherwise */
-pkgCache::PkgIterator pkgCache::FindPkg(const string &Name)
+/* Returns 0 on error, pointer to the package otherwise
+   The multiArch enabled methods will fallback to this one as it is (a bit)
+   faster for single arch environments and realworld is mostly singlearch… */
+pkgCache::PkgIterator pkgCache::SingleArchFindPkg(const string &Name)
 {
    // Look at the hash bucket
-   Package *Pkg = PkgP + HeaderP->HashTable[Hash(Name)];
+   Package *Pkg = PkgP + HeaderP->PkgHashTable[Hash(Name)];
    for (; Pkg != PkgP; Pkg = PkgP + Pkg->NextPackage)
    {
       if (Pkg->Name != 0 && StrP[Pkg->Name] == Name[0] &&
-	  stringcasecmp(Name,StrP + Pkg->Name) == 0)
-	 return PkgIterator(*this,Pkg);
+          stringcasecmp(Name,StrP + Pkg->Name) == 0)
+         return PkgIterator(*this,Pkg);
    }
    return PkgIterator(*this,0);
 }
 									/*}}}*/
+// Cache::FindPkg - Locate a package by name				/*{{{*/
+// ---------------------------------------------------------------------
+/* Returns 0 on error, pointer to the package otherwise */
+pkgCache::PkgIterator pkgCache::FindPkg(const string &Name) {
+	if (MultiArchCache() == false)
+		return SingleArchFindPkg(Name);
+	size_t const found = Name.find(':');
+	if (found == string::npos)
+		return FindPkg(Name, "native");
+	string const Arch = Name.substr(found+1);
+	if (Arch == "any")
+		return FindPkg(Name, "any");
+	return FindPkg(Name.substr(0, found), Arch);
+}
+									/*}}}*/
+// Cache::FindPkg - Locate a package by name				/*{{{*/
+// ---------------------------------------------------------------------
+/* Returns 0 on error, pointer to the package otherwise */
+pkgCache::PkgIterator pkgCache::FindPkg(const string &Name, string const &Arch) {
+	if (MultiArchCache() == false) {
+		if (Arch == "native" || Arch == "all" ||
+		    Arch == _config->Find("APT::Architecture"))
+			return SingleArchFindPkg(Name);
+		else
+			return PkgIterator(*this,0);
+	}
+	/* We make a detour via the GrpIterator here as
+	   on a multi-arch environment a group is easier to
+	   find than a package (less entries in the buckets) */
+	pkgCache::GrpIterator Grp = FindGrp(Name);
+	if (Grp.end() == true)
+		return PkgIterator(*this,0);
+
+	return Grp.FindPkg(Arch);
+}
+									/*}}}*/
+// Cache::FindGrp - Locate a group by name				/*{{{*/
+// ---------------------------------------------------------------------
+/* Returns End-Pointer on error, pointer to the group otherwise */
+pkgCache::GrpIterator pkgCache::FindGrp(const string &Name) {
+	if (unlikely(Name.empty() == true))
+		return GrpIterator(*this,0);
+
+	// Look at the hash bucket for the group
+	Group *Grp = GrpP + HeaderP->GrpHashTable[sHash(Name)];
+	for (; Grp != GrpP; Grp = GrpP + Grp->Next) {
+		if (Grp->Name != 0 && StrP[Grp->Name] == Name[0] &&
+		    stringcasecmp(Name, StrP + Grp->Name) == 0)
+			return GrpIterator(*this, Grp);
+	}
+
+	return GrpIterator(*this,0);
+}
+									/*}}}*/
 // Cache::CompTypeDeb - Return a string describing the compare type	/*{{{*/
 // ---------------------------------------------------------------------
 /* This returns a string representation of the dependency compare 
@@ -242,11 +301,77 @@ const char *pkgCache::Priority(unsigned char Prio)
    return 0;
 }
 									/*}}}*/
-// Bases for iterator classes						/*{{{*/
-void pkgCache::VerIterator::_dummy() {}
-void pkgCache::DepIterator::_dummy() {}
-void pkgCache::PrvIterator::_dummy() {}
-void pkgCache::DescIterator::_dummy() {}
+// GrpIterator::FindPkg - Locate a package by arch			/*{{{*/
+// ---------------------------------------------------------------------
+/* Returns an End-Pointer on error, pointer to the package otherwise */
+pkgCache::PkgIterator pkgCache::GrpIterator::FindPkg(string Arch) {
+	if (unlikely(IsGood() == false || S->FirstPackage == 0))
+		return PkgIterator(*Owner, 0);
+
+	static string const myArch = _config->Find("APT::Architecture");
+	/* Most of the time the package for our native architecture is
+	   the one we add at first to the cache, but this would be the
+	   last one we check, so we do it now. */
+	if (Arch == "native" || Arch == myArch) {
+		Arch = myArch;
+		pkgCache::Package *Pkg = Owner->PkgP + S->LastPackage;
+		if (stringcasecmp(Arch, Owner->StrP + Pkg->Arch) == 0)
+			return PkgIterator(*Owner, Pkg);
+	}
+
+	/* If we accept any package we simply return the "first"
+	   package in this group (the last one added). */
+	if (Arch == "any")
+		return PkgIterator(*Owner, Owner->PkgP + S->FirstPackage);
+
+	/* 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 */
+	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)
+			return PkgIterator(*Owner, Pkg);
+		if ((Owner->PkgP + S->LastPackage) == Pkg)
+			break;
+	}
+
+	return PkgIterator(*Owner, 0);
+}
+									/*}}}*/
+// GrpIterator::NextPkg - Locate the next package in the group		/*{{{*/
+// ---------------------------------------------------------------------
+/* Returns an End-Pointer on error, pointer to the package otherwise.
+   We can't simply ++ to the next as the next package of the last will
+   be from a different group (with the same hash value) */
+pkgCache::PkgIterator pkgCache::GrpIterator::NextPkg(pkgCache::PkgIterator const &LastPkg) {
+	if (unlikely(IsGood() == false || S->FirstPackage == 0 ||
+	    LastPkg.end() == true))
+		return PkgIterator(*Owner, 0);
+
+	if (S->LastPackage == LastPkg.Index())
+		return PkgIterator(*Owner, 0);
+
+	return PkgIterator(*Owner, Owner->PkgP + LastPkg->NextPackage);
+}
+									/*}}}*/
+// GrpIterator::operator ++ - Postfix incr				/*{{{*/
+// ---------------------------------------------------------------------
+/* This will advance to the next logical group in the hash table. */
+void pkgCache::GrpIterator::operator ++(int) 
+{
+   // Follow the current links
+   if (S != Owner->GrpP)
+      S = Owner->GrpP + S->Next;
+
+   // Follow the hash table
+   while (S == Owner->GrpP && (HashIndex+1) < (signed)_count(Owner->HeaderP->GrpHashTable))
+   {
+      HashIndex++;
+      S = Owner->GrpP + Owner->HeaderP->GrpHashTable[HashIndex];
+   }
+};
 									/*}}}*/
 // PkgIterator::operator ++ - Postfix incr				/*{{{*/
 // ---------------------------------------------------------------------
@@ -254,14 +379,14 @@ void pkgCache::DescIterator::_dummy() {}
 void pkgCache::PkgIterator::operator ++(int) 
 {
    // Follow the current links
-   if (Pkg != Owner->PkgP)
-      Pkg = Owner->PkgP + Pkg->NextPackage;
+   if (S != Owner->PkgP)
+      S = Owner->PkgP + S->NextPackage;
 
    // Follow the hash table
-   while (Pkg == Owner->PkgP && (HashIndex+1) < (signed)_count(Owner->HeaderP->HashTable))
+   while (S == Owner->PkgP && (HashIndex+1) < (signed)_count(Owner->HeaderP->PkgHashTable))
    {
       HashIndex++;
-      Pkg = Owner->PkgP + Owner->HeaderP->HashTable[HashIndex];
+      S = Owner->PkgP + Owner->HeaderP->PkgHashTable[HashIndex];
    }
 };
 									/*}}}*/
@@ -270,12 +395,12 @@ void pkgCache::PkgIterator::operator ++(int)
 /* By this we mean if it is either cleanly installed or cleanly removed. */
 pkgCache::PkgIterator::OkState pkgCache::PkgIterator::State() const
 {  
-   if (Pkg->InstState == pkgCache::State::ReInstReq ||
-       Pkg->InstState == pkgCache::State::HoldReInstReq)
+   if (S->InstState == pkgCache::State::ReInstReq ||
+       S->InstState == pkgCache::State::HoldReInstReq)
       return NeedsUnpack;
    
-   if (Pkg->CurrentState == pkgCache::State::UnPacked ||
-       Pkg->CurrentState == pkgCache::State::HalfConfigured)
+   if (S->CurrentState == pkgCache::State::UnPacked ||
+       S->CurrentState == pkgCache::State::HalfConfigured)
       // we leave triggers alone complettely. dpkg deals with
       // them in a hard-to-predict manner and if they get 
       // resolved by dpkg before apt run dpkg --configure on 
@@ -284,8 +409,8 @@ pkgCache::PkgIterator::OkState pkgCache::PkgIterator::State() const
       //Pkg->CurrentState == pkgCache::State::TriggersPending)
       return NeedsConfigure;
    
-   if (Pkg->CurrentState == pkgCache::State::HalfInstalled ||
-       Pkg->InstState != pkgCache::State::Ok)
+   if (S->CurrentState == pkgCache::State::HalfInstalled ||
+       S->InstState != pkgCache::State::Ok)
       return NeedsUnpack;
       
    return NeedsNothing;
@@ -332,7 +457,7 @@ operator<<(ostream& out, pkgCache::PkgIterator Pkg)
    string candidate = string(Pkg.CandVersion() == 0 ? "none" : Pkg.CandVersion());
    string newest = string(Pkg.VersionList().end() ? "none" : Pkg.VersionList().VerStr());
 
-   out << Pkg.Name() << " < " << current;
+   out << Pkg.Name() << " [ " << Pkg.Arch() << " ] < " << current;
    if (current != candidate)
       out << " -> " << candidate;
    if ( newest != "none" && candidate != newest)
@@ -341,17 +466,29 @@ operator<<(ostream& out, pkgCache::PkgIterator Pkg)
    return out;
 }
 									/*}}}*/
+// PkgIterator::FullName - Returns Name and (maybe) Architecture	/*{{{*/
+// ---------------------------------------------------------------------
+/* Returns a name:arch string */
+std::string pkgCache::PkgIterator::FullName(bool const &Pretty) const
+{
+   string fullname = Name();
+   if (Pretty == false ||
+       (strcmp(Arch(), "all") != 0 && _config->Find("APT::Architecture") != Arch()))
+      return fullname.append(":").append(Arch());
+   return fullname;
+}
+									/*}}}*/
 // DepIterator::IsCritical - Returns true if the dep is important	/*{{{*/
 // ---------------------------------------------------------------------
 /* Currently critical deps are defined as depends, predepends and
    conflicts (including dpkg's Breaks fields). */
 bool pkgCache::DepIterator::IsCritical()
 {
-   if (Dep->Type == pkgCache::Dep::Conflicts ||
-       Dep->Type == pkgCache::Dep::DpkgBreaks ||
-       Dep->Type == pkgCache::Dep::Obsoletes ||
-       Dep->Type == pkgCache::Dep::Depends ||
-       Dep->Type == pkgCache::Dep::PreDepends)
+   if (S->Type == pkgCache::Dep::Conflicts ||
+       S->Type == pkgCache::Dep::DpkgBreaks ||
+       S->Type == pkgCache::Dep::Obsoletes ||
+       S->Type == pkgCache::Dep::Depends ||
+       S->Type == pkgCache::Dep::PreDepends)
       return true;
    return false;
 }
@@ -430,12 +567,12 @@ pkgCache::Version **pkgCache::DepIterator::AllTargets()
       // Walk along the actual package providing versions
       for (VerIterator I = DPkg.VersionList(); I.end() == false; I++)
       {
-	 if (Owner->VS->CheckDep(I.VerStr(),Dep->CompareOp,TargetVer()) == false)
+	 if (Owner->VS->CheckDep(I.VerStr(),S->CompareOp,TargetVer()) == false)
 	    continue;
 
-	 if ((Dep->Type == pkgCache::Dep::Conflicts ||
-	      Dep->Type == pkgCache::Dep::DpkgBreaks ||
-	      Dep->Type == pkgCache::Dep::Obsoletes) &&
+	 if ((S->Type == pkgCache::Dep::Conflicts ||
+	      S->Type == pkgCache::Dep::DpkgBreaks ||
+	      S->Type == pkgCache::Dep::Obsoletes) &&
 	     ParentPkg() == I.ParentPkg())
 	    continue;
 	 
@@ -447,12 +584,12 @@ pkgCache::Version **pkgCache::DepIterator::AllTargets()
       // Follow all provides
       for (PrvIterator I = DPkg.ProvidesList(); I.end() == false; I++)
       {
-	 if (Owner->VS->CheckDep(I.ProvideVersion(),Dep->CompareOp,TargetVer()) == false)
+	 if (Owner->VS->CheckDep(I.ProvideVersion(),S->CompareOp,TargetVer()) == false)
 	    continue;
 	 
-	 if ((Dep->Type == pkgCache::Dep::Conflicts ||
-	      Dep->Type == pkgCache::Dep::DpkgBreaks ||
-	      Dep->Type == pkgCache::Dep::Obsoletes) &&
+	 if ((S->Type == pkgCache::Dep::Conflicts ||
+	      S->Type == pkgCache::Dep::DpkgBreaks ||
+	      S->Type == pkgCache::Dep::Obsoletes) &&
 	     ParentPkg() == I.OwnerPkg())
 	    continue;
 	 
@@ -490,7 +627,7 @@ void pkgCache::DepIterator::GlobOr(DepIterator &Start,DepIterator &End)
    End = *this;
    for (bool LastOR = true; end() == false && LastOR == true;)
    {
-      LastOR = (Dep->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or;
+      LastOR = (S->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or;
       (*this)++;
       if (LastOR == true)
 	 End = (*this);
@@ -545,6 +682,23 @@ bool pkgCache::VerIterator::Automatic() const
    return false;
 }
 									/*}}}*/
+// VerIterator::Pseudo - Check if this version is a pseudo one		/*{{{*/
+// ---------------------------------------------------------------------
+/* Sometimes you have the need to express dependencies with versions
+   which doesn't really exist or exist multiply times for "different"
+   packages. We need these versions for dependency resolution but they
+   are a problem everytime we need to download/install something. */
+bool pkgCache::VerIterator::Pseudo() const
+{
+   if (S->MultiArch == pkgCache::Version::All &&
+	   strcmp(Arch(true),"all") != 0)
+   {
+	   GrpIterator const Grp = ParentPkg().Group();
+	   return (Grp->LastPackage != Grp->FirstPackage);
+   }
+   return false;
+}
+									/*}}}*/
 // VerIterator::NewestFile - Return the newest file version relation	/*{{{*/
 // ---------------------------------------------------------------------
 /* This looks at the version numbers associated with all of the sources
@@ -625,7 +779,9 @@ string pkgCache::VerIterator::RelStr()
 	 else
 	    Res += File.Site();
       }      
-   }   
+   }
+   if (S->ParentPkg != 0)
+      Res.append(" [").append(Arch()).append("]");
    return Res;
 }
 									/*}}}*/
@@ -640,7 +796,7 @@ bool pkgCache::PkgFileIterator::IsOk()
    if (stat(FileName(),&Buf) != 0)
       return false;
 
-   if (Buf.st_size != (signed)File->Size || Buf.st_mtime != File->mtime)
+   if (Buf.st_size != (signed)S->Size || Buf.st_mtime != S->mtime)
       return false;
 
    return true;
@@ -664,6 +820,8 @@ string pkgCache::PkgFileIterator::RelStr()
       Res = Res + (Res.empty() == true?"l=":",l=")  + Label();
    if (Component() != 0)
       Res = Res + (Res.empty() == true?"c=":",c=")  + Component();
+   if (Architecture() != 0)
+      Res = Res + (Res.empty() == true?"b=":",b=")  + Architecture();
    return Res;
 }
 									/*}}}*/

+ 40 - 14
apt-pkg/pkgcache.h

@@ -32,6 +32,7 @@ class pkgCache								/*{{{*/
    public:
    // Cache element predeclarations
    struct Header;
+   struct Group;
    struct Package;
    struct PackageFile;
    struct Version;
@@ -43,6 +44,8 @@ class pkgCache								/*{{{*/
    struct DescFile;
    
    // Iterators
+   template<typename Str, typename Itr> class Iterator;
+   class GrpIterator;
    class PkgIterator;
    class VerIterator;
    class DescIterator;
@@ -51,14 +54,6 @@ class pkgCache								/*{{{*/
    class PkgFileIterator;
    class VerFileIterator;
    class DescFileIterator;
-   friend class PkgIterator;
-   friend class VerIterator;
-   friend class DescInterator;
-   friend class DepIterator;
-   friend class PrvIterator;
-   friend class PkgFileIterator;
-   friend class VerFileIterator;
-   friend class DescFileIterator;
    
    class Namespace;
    
@@ -104,6 +99,7 @@ class pkgCache								/*{{{*/
    
    // Pointers to the arrays of items
    Header *HeaderP;
+   Group *GrpP;
    Package *PkgP;
    VerFile *VerFileP;
    DescFile *DescFileP;
@@ -128,13 +124,20 @@ class pkgCache								/*{{{*/
    const char *Priority(unsigned char Priority);
    
    // Accessors
+   GrpIterator FindGrp(const string &Name);
    PkgIterator FindPkg(const string &Name);
+   PkgIterator FindPkg(const string &Name, const string &Arch);
+
    Header &Head() {return *HeaderP;};
+   inline GrpIterator GrpBegin();
+   inline GrpIterator GrpEnd();
    inline PkgIterator PkgBegin();
    inline PkgIterator PkgEnd();
    inline PkgFileIterator FileBegin();
    inline PkgFileIterator FileEnd();
 
+   inline bool MultiArchCache() const { return MultiArchEnabled; };
+
    // Make me a function
    pkgVersioningSystem *VS;
    
@@ -145,6 +148,10 @@ class pkgCache								/*{{{*/
    
    pkgCache(MMap *Map,bool DoMap = true);
    virtual ~pkgCache() {};
+
+private:
+   bool MultiArchEnabled;
+   PkgIterator SingleArchFindPkg(const string &Name);
 };
 									/*}}}*/
 // Header structure							/*{{{*/
@@ -168,6 +175,7 @@ struct pkgCache::Header
    unsigned short DescFileSz;
    
    // Structure counts
+   unsigned long GroupCount;
    unsigned long PackageCount;
    unsigned long VersionCount;
    unsigned long DescriptionCount;
@@ -187,22 +195,36 @@ struct pkgCache::Header
 
    /* Allocation pools, there should be one of these for each structure
       excluding the header */
-   DynamicMMap::Pool Pools[8];
+   DynamicMMap::Pool Pools[9];
    
-   // Rapid package name lookup
-   map_ptrloc HashTable[2*1048];
+   // Rapid package and group name lookup
+   // Notice: Increase only both table sizes as the
+   // hashmethod assume the size of the Pkg one
+   map_ptrloc PkgHashTable[2*1048];
+   map_ptrloc GrpHashTable[2*1048];
 
    bool CheckSizes(Header &Against) const;
    Header();
 };
 									/*}}}*/
+struct pkgCache::Group {						/*{{{*/
+	map_ptrloc Name;	// Stringtable
+
+	// Linked List
+	map_ptrloc FirstPackage;// Package
+	map_ptrloc LastPackage;	// Package
+	map_ptrloc Next;	// Group
+};
+									/*}}}*/
 struct pkgCache::Package						/*{{{*/
 {
    // Pointers
    map_ptrloc Name;              // Stringtable
+   map_ptrloc Arch;              // StringTable (StringItem)
    map_ptrloc VersionList;       // Version
    map_ptrloc CurrentVer;        // Version
    map_ptrloc Section;           // StringTable (StringItem)
+   map_ptrloc Group;             // Group the Package belongs to
       
    // Linked list 
    map_ptrloc NextPackage;       // Package
@@ -260,8 +282,8 @@ struct pkgCache::Version						/*{{{*/
 {
    map_ptrloc VerStr;            // Stringtable
    map_ptrloc Section;           // StringTable (StringItem)
-   map_ptrloc Arch;              // StringTable
-      
+   enum {None, All, Foreign, Same, Allowed} MultiArch;
+
    // Lists
    map_ptrloc FileList;          // VerFile
    map_ptrloc NextVer;           // Version
@@ -324,6 +346,10 @@ struct pkgCache::StringItem						/*{{{*/
 									/*}}}*/
 #include <apt-pkg/cacheiterators.h>
 
+inline pkgCache::GrpIterator pkgCache::GrpBegin() 
+       {return GrpIterator(*this);};
+inline pkgCache::GrpIterator pkgCache::GrpEnd() 
+       {return GrpIterator(*this,GrpP);};
 inline pkgCache::PkgIterator pkgCache::PkgBegin() 
        {return PkgIterator(*this);};
 inline pkgCache::PkgIterator pkgCache::PkgEnd() 
@@ -337,7 +363,7 @@ inline pkgCache::PkgFileIterator pkgCache::FileEnd()
 class pkgCache::Namespace						/*{{{*/
 {   
    public:
-
+   typedef pkgCache::GrpIterator GrpIterator;
    typedef pkgCache::PkgIterator PkgIterator;
    typedef pkgCache::VerIterator VerIterator;
    typedef pkgCache::DescIterator DescIterator;

+ 238 - 74
apt-pkg/pkgcachegen.cc

@@ -18,6 +18,7 @@
 #include <apt-pkg/progress.h>
 #include <apt-pkg/sourcelist.h>
 #include <apt-pkg/configuration.h>
+#include <apt-pkg/aptconfiguration.h>
 #include <apt-pkg/strutl.h>
 #include <apt-pkg/sptr.h>
 #include <apt-pkg/pkgsystem.h>
@@ -38,7 +39,7 @@ typedef vector<pkgIndexFile *>::iterator FileIterator;
 
 // CacheGenerator::pkgCacheGenerator - Constructor			/*{{{*/
 // ---------------------------------------------------------------------
-/* We set the diry flag and make sure that is written to the disk */
+/* We set the dirty flag and make sure that is written to the disk */
 pkgCacheGenerator::pkgCacheGenerator(DynamicMMap *pMap,OpProgress *Prog) :
 		    Map(*pMap), Cache(pMap,false), Progress(Prog),
 		    FoundFileDeps(0)
@@ -107,13 +108,26 @@ bool pkgCacheGenerator::MergeList(ListParser &List,
    unsigned int Counter = 0;
    while (List.Step() == true)
    {
-      // Get a pointer to the package structure
-      string PackageName = List.Package();
+      string const PackageName = List.Package();
       if (PackageName.empty() == true)
 	 return false;
-      
+
+      /* As we handle Arch all packages as architecture bounded
+         we add all information to every (simulated) arch package */
+      std::vector<string> genArch;
+      if (List.ArchitectureAll() == true) {
+	 genArch = APT::Configuration::getArchitectures();
+	 if (genArch.size() != 1)
+	    genArch.push_back("all");
+      } else
+	 genArch.push_back(List.Architecture());
+
+      for (std::vector<string>::const_iterator arch = genArch.begin();
+	   arch != genArch.end(); ++arch)
+      {
+      // Get a pointer to the package structure
       pkgCache::PkgIterator Pkg;
-      if (NewPackage(Pkg,PackageName) == false)
+      if (NewPackage(Pkg, PackageName, *arch) == false)
 	 return _error->Error(_("Error occurred while processing %s (NewPackage)"),PackageName.c_str());
       Counter++;
       if (Counter % 100 == 0 && Progress != 0)
@@ -175,17 +189,22 @@ bool pkgCacheGenerator::MergeList(ListParser &List,
       pkgCache::VerIterator Ver = Pkg.VersionList();
       map_ptrloc *LastVer = &Pkg->VersionList;
       int Res = 1;
+      unsigned long const Hash = List.VersionHash();
       for (; Ver.end() == false; LastVer = &Ver->NextVer, Ver++)
       {
 	 Res = Cache.VS->CmpVersion(Version,Ver.VerStr());
-	 if (Res >= 0)
+	 // Version is higher as current version - insert here
+	 if (Res > 0)
 	    break;
+	 // Versionstrings are equal - is hash also equal?
+	 if (Res == 0 && Ver->Hash == Hash)
+	    break;
+	 // proceed with the next till we have either the right
+	 // or we found another version (which will be lower)
       }
-      
-      /* We already have a version for this item, record that we
-         saw it */
-      unsigned long Hash = List.VersionHash();
-      if (Res == 0 && Ver->Hash == Hash)
+
+      /* We already have a version for this item, record that we saw it */
+      if (Res == 0 && Ver.end() == false && Ver->Hash == Hash)
       {
 	 if (List.UsePackage(Pkg,Ver) == false)
 	    return _error->Error(_("Error occurred while processing %s (UsePackage2)"),
@@ -204,17 +223,6 @@ bool pkgCacheGenerator::MergeList(ListParser &List,
 	 }
 	 
 	 continue;
-      }      
-
-      // Skip to the end of the same version set.
-      if (Res == 0)
-      {
-	 for (; Ver.end() == false; LastVer = &Ver->NextVer, Ver++)
-	 {
-	    Res = Cache.VS->CmpVersion(Version,Ver.VerStr());
-	    if (Res != 0)
-	       break;
-	 }
       }
 
       // Add a new version
@@ -256,6 +264,7 @@ bool pkgCacheGenerator::MergeList(ListParser &List,
 
       if ((*LastDesc == 0 && _error->PendingError()) || NewFileDesc(Desc,List) == false)
 	 return _error->Error(_("Error occurred while processing %s (NewFileDesc2)"),PackageName.c_str());
+      }
    }
 
    FoundFileDeps |= List.HasFileDeps();
@@ -323,33 +332,80 @@ bool pkgCacheGenerator::MergeFileProvides(ListParser &List)
    return true;
 }
 									/*}}}*/
-// CacheGenerator::NewPackage - Add a new package			/*{{{*/
+// CacheGenerator::NewGroup - Add a new group				/*{{{*/
 // ---------------------------------------------------------------------
-/* This creates a new package structure and adds it to the hash table */
-bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator &Pkg,const string &Name)
+/* This creates a new group structure and adds it to the hash table */
+bool pkgCacheGenerator::NewGroup(pkgCache::GrpIterator &Grp, const string &Name)
 {
-   Pkg = Cache.FindPkg(Name);
-   if (Pkg.end() == false)
+   Grp = Cache.FindGrp(Name);
+   if (Grp.end() == false)
       return true;
 
    // Get a structure
-   unsigned long Package = Map.Allocate(sizeof(pkgCache::Package));
-   if (Package == 0)
+   unsigned long const Group = Map.Allocate(sizeof(pkgCache::Group));
+   if (unlikely(Group == 0))
       return false;
-   
-   Pkg = pkgCache::PkgIterator(Cache,Cache.PkgP + Package);
-   
+
+   Grp = pkgCache::GrpIterator(Cache, Cache.GrpP + Group);
+   Grp->Name = Map.WriteString(Name);
+   if (unlikely(Grp->Name == 0))
+      return false;
+
    // Insert it into the hash table
-   unsigned long Hash = Cache.Hash(Name);
-   Pkg->NextPackage = Cache.HeaderP->HashTable[Hash];
-   Cache.HeaderP->HashTable[Hash] = Package;
-   
-   // Set the name and the ID
-   Pkg->Name = Map.WriteString(Name);
-   if (Pkg->Name == 0)
+   unsigned long const Hash = Cache.Hash(Name);
+   Grp->Next = Cache.HeaderP->GrpHashTable[Hash];
+   Cache.HeaderP->GrpHashTable[Hash] = Group;
+
+   Cache.HeaderP->GroupCount++;
+
+   return true;
+}
+									/*}}}*/
+// CacheGenerator::NewPackage - Add a new package			/*{{{*/
+// ---------------------------------------------------------------------
+/* This creates a new package structure and adds it to the hash table */
+bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator &Pkg,const string &Name,
+					const string &Arch) {
+   pkgCache::GrpIterator Grp;
+   if (unlikely(NewGroup(Grp, Name) == false))
+      return false;
+
+   Pkg = Grp.FindPkg(Arch);
+      if (Pkg.end() == false)
+	 return true;
+
+   // Get a structure
+   unsigned long const Package = Map.Allocate(sizeof(pkgCache::Package));
+   if (unlikely(Package == 0))
+      return false;
+   Pkg = pkgCache::PkgIterator(Cache,Cache.PkgP + Package);
+
+   // Insert the package into our package list
+   if (Grp->FirstPackage == 0) // the group is new
+   {
+      // Insert it into the hash table
+      unsigned long const Hash = Cache.Hash(Name);
+      Pkg->NextPackage = Cache.HeaderP->PkgHashTable[Hash];
+      Cache.HeaderP->PkgHashTable[Hash] = Package;
+      Grp->FirstPackage = 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;
+   }
+   Grp->LastPackage = Package;
+
+   // Set the name, arch and the ID
+   Pkg->Name = Grp->Name;
+   Pkg->Group = Grp.Index();
+   Pkg->Arch = WriteUniqString(Arch.c_str());
+   if (unlikely(Pkg->Arch == 0))
       return false;
    Pkg->ID = Cache.HeaderP->PackageCount++;
-   
+
    return true;
 }
 									/*}}}*/
@@ -468,21 +524,95 @@ map_ptrloc pkgCacheGenerator::NewDescription(pkgCache::DescIterator &Desc,
    return Description;
 }
 									/*}}}*/
-// ListParser::NewDepends - Create a dependency element			/*{{{*/
+// CacheGenerator::FinishCache - do various finish operations		/*{{{*/
+// ---------------------------------------------------------------------
+/* This prepares the Cache for delivery */
+bool pkgCacheGenerator::FinishCache(OpProgress &Progress)
+{
+   // FIXME: add progress reporting for this operation
+   // Do we have different architectures in your groups ?
+   vector<string> archs = APT::Configuration::getArchitectures();
+   if (archs.size() > 1)
+   {
+      // Create Conflicts in between the group
+      for (pkgCache::GrpIterator G = GetCache().GrpBegin(); G.end() != true; G++)
+      {
+	 string const PkgName = G.Name();
+	 for (pkgCache::PkgIterator P = G.PackageList(); P.end() != true; P = G.NextPkg(P))
+	 {
+	    if (strcmp(P.Arch(),"all") == 0)
+	       continue;
+	    pkgCache::PkgIterator allPkg;
+	    for (pkgCache::VerIterator V = P.VersionList(); V.end() != true; V++)
+	    {
+	       string const Arch = V.Arch(true);
+	       map_ptrloc *OldDepLast = NULL;
+	       /* MultiArch handling introduces a lot of implicit Dependencies:
+		- MultiArch: same → Co-Installable if they have the same version
+		- Architecture: all → Need to be Co-Installable for internal reasons
+		- All others conflict with all other group members */
+	       bool const coInstall = (V->MultiArch == pkgCache::Version::All ||
+					V->MultiArch == pkgCache::Version::Same);
+	       if (V->MultiArch == pkgCache::Version::All && allPkg.end() == true)
+		  allPkg = G.FindPkg("all");
+	       for (vector<string>::const_iterator A = archs.begin(); A != archs.end(); ++A)
+	       {
+		  if (*A == Arch)
+		     continue;
+		  /* We allow only one installed arch at the time
+		     per group, therefore each group member conflicts
+		     with all other group members */
+		  pkgCache::PkgIterator D = G.FindPkg(*A);
+		  if (D.end() == true)
+		     continue;
+		  if (coInstall == true)
+		  {
+		     // Replaces: ${self}:other ( << ${binary:Version})
+		     NewDepends(D, V, V.VerStr(),
+				pkgCache::Dep::Less, pkgCache::Dep::Replaces,
+				OldDepLast);
+		     // Breaks: ${self}:other (!= ${binary:Version})
+		     NewDepends(D, V, V.VerStr(),
+				pkgCache::Dep::Less, pkgCache::Dep::DpkgBreaks,
+				OldDepLast);
+		     NewDepends(D, V, V.VerStr(),
+				pkgCache::Dep::Greater, pkgCache::Dep::DpkgBreaks,
+				OldDepLast);
+		     if (V->MultiArch == pkgCache::Version::All)
+		     {
+			// Depend on ${self}:all which does depend on nothing
+			NewDepends(allPkg, V, V.VerStr(),
+				   pkgCache::Dep::Equals, pkgCache::Dep::Depends,
+				   OldDepLast);
+		     }
+		  } else {
+			// Conflicts: ${self}:other
+			NewDepends(D, V, "",
+				   pkgCache::Dep::NoOp, pkgCache::Dep::Conflicts,
+				   OldDepLast);
+		  }
+	       }
+	    }
+	 }
+      }
+   }
+   return true;
+}
+									/*}}}*/
+// CacheGenerator::NewDepends - Create a dependency element		/*{{{*/
 // ---------------------------------------------------------------------
 /* This creates a dependency element in the tree. It is linked to the
    version and to the package that it is pointing to. */
-bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver,
-					       const string &PackageName,
-					       const string &Version,
-					       unsigned int Op,
-					       unsigned int Type)
+bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator &Pkg,
+				   pkgCache::VerIterator &Ver,
+				   string const &Version,
+				   unsigned int const &Op,
+				   unsigned int const &Type,
+				   map_ptrloc *OldDepLast)
 {
-   pkgCache &Cache = Owner->Cache;
-   
    // Get a structure
-   unsigned long Dependency = Owner->Map.Allocate(sizeof(pkgCache::Dependency));
-   if (Dependency == 0)
+   unsigned long const Dependency = Map.Allocate(sizeof(pkgCache::Dependency));
+   if (unlikely(Dependency == 0))
       return false;
    
    // Fill it in
@@ -491,12 +621,7 @@ bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver,
    Dep->Type = Type;
    Dep->CompareOp = Op;
    Dep->ID = Cache.HeaderP->DependsCount++;
-   
-   // Locate the target package
-   pkgCache::PkgIterator Pkg;
-   if (Owner->NewPackage(Pkg,PackageName) == false)
-      return false;
-   
+
    // Probe the reverse dependency list for a version string that matches
    if (Version.empty() == false)
    {
@@ -504,29 +629,23 @@ bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver,
 	 if (I->Version != 0 && I.TargetVer() == Version)
 	    Dep->Version = I->Version;*/
       if (Dep->Version == 0)
-	 if ((Dep->Version = WriteString(Version)) == 0)
+	 if (unlikely((Dep->Version = Map.WriteString(Version)) == 0))
 	    return false;
    }
-      
+
    // Link it to the package
    Dep->Package = Pkg.Index();
    Dep->NextRevDepends = Pkg->RevDepends;
    Pkg->RevDepends = Dep.Index();
-   
-   /* Link it to the version (at the end of the list)
-      Caching the old end point speeds up generation substantially */
-   if (OldDepVer != Ver)
+
+   // Do we know where to link the Dependency to?
+   if (OldDepLast == NULL)
    {
       OldDepLast = &Ver->DependsList;
       for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; D++)
 	 OldDepLast = &D->NextDepends;
-      OldDepVer = Ver;
    }
 
-   // Is it a file dependency?
-   if (PackageName[0] == '/')
-      FoundFileDeps = true;
-   
    Dep->NextDepends = *OldDepLast;
    *OldDepLast = Dep.Index();
    OldDepLast = &Dep->NextDepends;
@@ -534,22 +653,58 @@ bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver,
    return true;
 }
 									/*}}}*/
+// ListParser::NewDepends - Create the environment for a new dependency	/*{{{*/
+// ---------------------------------------------------------------------
+/* This creates a Group and the Package to link this dependency to if
+   needed and handles also the caching of the old endpoint */
+bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver,
+					       const string &PackageName,
+					       const string &Arch,
+					       const string &Version,
+					       unsigned int Op,
+					       unsigned int Type)
+{
+   pkgCache::GrpIterator Grp;
+   if (unlikely(Owner->NewGroup(Grp, PackageName) == false))
+      return false;
+
+   // Locate the target package
+   pkgCache::PkgIterator Pkg = Grp.FindPkg(Arch);
+   if (Pkg.end() == true) {
+      if (unlikely(Owner->NewPackage(Pkg, PackageName, Arch) == false))
+	 return false;
+   }
+
+   // Is it a file dependency?
+   if (unlikely(PackageName[0] == '/'))
+      FoundFileDeps = true;
+
+   /* Caching the old end point speeds up generation substantially */
+   if (OldDepVer != Ver) {
+      OldDepLast = NULL;
+      OldDepVer = Ver;
+   }
+
+   return Owner->NewDepends(Pkg, Ver, Version, Op, Type, OldDepLast);
+}
+									/*}}}*/
 // ListParser::NewProvides - Create a Provides element			/*{{{*/
 // ---------------------------------------------------------------------
 /* */
 bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver,
-					        const string &PackageName,
+					        const string &PkgName,
+						const string &PkgArch,
 						const string &Version)
 {
    pkgCache &Cache = Owner->Cache;
 
    // We do not add self referencing provides
-   if (Ver.ParentPkg().Name() == PackageName)
+   if (Ver.ParentPkg().Name() == PkgName && PkgArch == Ver.Arch(true))
       return true;
    
    // Get a structure
-   unsigned long Provides = Owner->Map.Allocate(sizeof(pkgCache::Provides));
-   if (Provides == 0)
+   unsigned long const Provides = Owner->Map.Allocate(sizeof(pkgCache::Provides));
+   if (unlikely(Provides == 0))
       return false;
    Cache.HeaderP->ProvidesCount++;
    
@@ -558,12 +713,12 @@ bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver,
    Prv->Version = Ver.Index();
    Prv->NextPkgProv = Ver->ProvidesList;
    Ver->ProvidesList = Prv.Index();
-   if (Version.empty() == false && (Prv->ProvideVersion = WriteString(Version)) == 0)
+   if (Version.empty() == false && unlikely((Prv->ProvideVersion = WriteString(Version)) == 0))
       return false;
    
    // Locate the target package
    pkgCache::PkgIterator Pkg;
-   if (Owner->NewPackage(Pkg,PackageName) == false)
+   if (unlikely(Owner->NewPackage(Pkg,PkgName, PkgArch) == false))
       return false;
    
    // Link it to the package
@@ -923,6 +1078,9 @@ bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress,
       if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
 		     Files.begin()+EndOfSource,Files.end()) == false)
 	 return false;
+
+      // FIXME: move me to a better place
+      Gen.FinishCache(Progress);
    }
    else
    {
@@ -965,6 +1123,9 @@ bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress,
       if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
 		     Files.begin()+EndOfSource,Files.end()) == false)
 	 return false;
+
+      // FIXME: move me to a better place
+      Gen.FinishCache(Progress);
    }
    if (Debug == true)
       std::clog << "Caches are ready for shipping" << std::endl;
@@ -1012,7 +1173,10 @@ bool pkgMakeOnlyStatusCache(OpProgress &Progress,DynamicMMap **OutMap)
    if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
 		  Files.begin()+EndOfSource,Files.end()) == false)
       return false;
-   
+
+   // FIXME: move me to a better place
+   Gen.FinishCache(Progress);
+
    if (_error->PendingError() == true)
       return false;
    *OutMap = Map.UnGuard();

+ 12 - 5
apt-pkg/pkgcachegen.h

@@ -51,9 +51,13 @@ class pkgCacheGenerator							/*{{{*/
    // Flag file dependencies
    bool FoundFileDeps;
    
-   bool NewPackage(pkgCache::PkgIterator &Pkg,const string &PkgName);
+   bool NewGroup(pkgCache::GrpIterator &Grp,const string &Name);
+   bool NewPackage(pkgCache::PkgIterator &Pkg,const string &Name, const string &Arch);
    bool NewFileVer(pkgCache::VerIterator &Ver,ListParser &List);
    bool NewFileDesc(pkgCache::DescIterator &Desc,ListParser &List);
+   bool NewDepends(pkgCache::PkgIterator &Pkg, pkgCache::VerIterator &Ver,
+		   string const &Version, unsigned int const &Op,
+		   unsigned int const &Type, map_ptrloc *OldDepLast);
    unsigned long NewVersion(pkgCache::VerIterator &Ver,const string &VerStr,unsigned long Next);
    map_ptrloc NewDescription(pkgCache::DescIterator &Desc,const string &Lang,const MD5SumValue &md5sum,map_ptrloc Next);
 
@@ -72,7 +76,8 @@ class pkgCacheGenerator							/*{{{*/
 
    bool HasFileDeps() {return FoundFileDeps;};
    bool MergeFileProvides(ListParser &List);
-      
+   bool FinishCache(OpProgress &Progress);
+
    pkgCacheGenerator(DynamicMMap *Map,OpProgress *Progress);
    ~pkgCacheGenerator();
 };
@@ -96,16 +101,18 @@ class pkgCacheGenerator::ListParser
    inline unsigned long WriteUniqString(const char *S,unsigned int Size) {return Owner->WriteUniqString(S,Size);};
    inline unsigned long WriteString(const string &S) {return Owner->Map.WriteString(S);};
    inline unsigned long WriteString(const char *S,unsigned int Size) {return Owner->Map.WriteString(S,Size);};
-   bool NewDepends(pkgCache::VerIterator Ver,const string &Package,
+   bool NewDepends(pkgCache::VerIterator Ver,const string &Package, const string &Arch,
 		   const string &Version,unsigned int Op,
 		   unsigned int Type);
-   bool NewProvides(pkgCache::VerIterator Ver,const string &Package,
-		    const string &Version);
+   bool NewProvides(pkgCache::VerIterator Ver,const string &PkgName,
+		    const string &PkgArch, const string &Version);
    
    public:
    
    // These all operate against the current section
    virtual string Package() = 0;
+   virtual string Architecture() = 0;
+   virtual bool ArchitectureAll() = 0;
    virtual string Version() = 0;
    virtual bool NewVersion(pkgCache::VerIterator Ver) = 0;
    virtual string Description() = 0;

+ 22 - 19
apt-pkg/policy.cc

@@ -201,35 +201,38 @@ pkgCache::VerIterator pkgPolicy::GetCandidateVer(pkgCache::PkgIterator Pkg)
 void pkgPolicy::CreatePin(pkgVersionMatch::MatchType Type,string Name,
 			  string Data,signed short Priority)
 {
-   Pin *P = 0;
-   
    if (Name.empty() == true)
-      P = &*Defaults.insert(Defaults.end(),PkgPin());
-   else
    {
-      // Get a spot to put the pin
-      pkgCache::PkgIterator Pkg = Cache->FindPkg(Name);
-      if (Pkg.end() == true)
+      Pin *P = &*Defaults.insert(Defaults.end(),PkgPin());
+      P->Type = Type;
+      P->Priority = Priority;
+      P->Data = Data;
+      return;
+   }
+
+   // Get a spot to put the pin
+   pkgCache::GrpIterator Grp = Cache->FindGrp(Name);
+   for (pkgCache::PkgIterator Pkg = Grp.FindPkg("any");
+	Pkg.end() != true; Pkg = Grp.NextPkg(Pkg))
+   {
+      Pin *P = 0;
+      if (Pkg.end() == false)
+	 P = Pins + Pkg->ID;
+      else
       {
 	 // Check the unmatched table
-	 for (vector<PkgPin>::iterator I = Unmatched.begin(); 
+	 for (vector<PkgPin>::iterator I = Unmatched.begin();
 	      I != Unmatched.end() && P == 0; I++)
 	    if (I->Pkg == Name)
 	       P = &*I;
-	 
+
 	 if (P == 0)
-	    P = &*Unmatched.insert(Unmatched.end(),PkgPin());      
+	    P = &*Unmatched.insert(Unmatched.end(),PkgPin());
       }
-      else
-      {
-	 P = Pins + Pkg->ID;
-      }      
+      P->Type = Type;
+      P->Priority = Priority;
+      P->Data = Data;
    }
-   
-   // Set..
-   P->Type = Type;
-   P->Priority = Priority;
-   P->Data = Data;
 }
 									/*}}}*/
 // Policy::GetMatch - Get the matching version for a package pin	/*{{{*/

+ 45 - 36
apt-pkg/sourcelist.cc

@@ -72,13 +72,51 @@ bool pkgSourceList::Type::FixupURI(string &URI) const
    Weird types may override this. */
 bool pkgSourceList::Type::ParseLine(vector<metaIndex *> &List,
 				    const char *Buffer,
-				    unsigned long CurLine,
-				    string File) const
+				    unsigned long const &CurLine,
+				    string const &File) const
 {
+   for (;Buffer != 0 && isspace(*Buffer); ++Buffer); // Skip whitespaces
+
+   // Parse option field if it exists
+   // e.g.: [ option1=value1 option2=value2 ]
+   map<string, string> Options;
+   if (Buffer != 0 && Buffer[0] == '[')
+   {
+      ++Buffer; // ignore the [
+      for (;Buffer != 0 && isspace(*Buffer); ++Buffer); // Skip whitespaces
+      while (*Buffer != ']')
+      {
+	 // get one option, e.g. option1=value1
+	 string option;
+	 if (ParseQuoteWord(Buffer,option) == false)
+	    return _error->Error(_("Malformed line %lu in source list %s ([option] unparseable)"),CurLine,File.c_str());
+
+	 if (option.length() < 3)
+	    return _error->Error(_("Malformed line %lu in source list %s ([option] too short)"),CurLine,File.c_str());
+
+	 size_t const needle = option.find('=');
+	 if (needle == string::npos)
+	    return _error->Error(_("Malformed line %lu in source list %s ([%s] is not an assignment)"),CurLine,File.c_str(), option.c_str());
+
+	 string const key = string(option, 0, needle);
+	 string const value = string(option, needle + 1, option.length());
+
+	 if (key.empty() == true)
+	    return _error->Error(_("Malformed line %lu in source list %s ([%s] has no key)"),CurLine,File.c_str(), option.c_str());
+
+	 if (value.empty() == true)
+	    return _error->Error(_("Malformed line %lu in source list %s ([%s] key %s has no value)"),CurLine,File.c_str(),option.c_str(),key.c_str());
+
+	 Options[key] = value;
+      }
+      ++Buffer; // ignore the ]
+      for (;Buffer != 0 && isspace(*Buffer); ++Buffer); // Skip whitespaces
+   }
+
    string URI;
    string Dist;
-   string Section;   
-   
+   string Section;
+
    if (ParseQuoteWord(Buffer,URI) == false)
       return _error->Error(_("Malformed line %lu in source list %s (URI)"),CurLine,File.c_str());
    if (ParseQuoteWord(Buffer,Dist) == false)
@@ -93,7 +131,7 @@ bool pkgSourceList::Type::ParseLine(vector<metaIndex *> &List,
       if (ParseQuoteWord(Buffer,Section) == true)
 	 return _error->Error(_("Malformed line %lu in source list %s (absolute dist)"),CurLine,File.c_str());
       Dist = SubstVar(Dist,"$(ARCH)",_config->Find("APT::Architecture"));
-      return CreateItem(List,URI,Dist,Section);
+      return CreateItem(List, URI, Dist, Section, Options);
    }
    
    // Grab the rest of the dists
@@ -102,7 +140,7 @@ bool pkgSourceList::Type::ParseLine(vector<metaIndex *> &List,
    
    do
    {
-      if (CreateItem(List,URI,Dist,Section) == false)
+      if (CreateItem(List, URI, Dist, Section, Options) == false)
 	 return false;
    }
    while (ParseQuoteWord(Buffer,Section) == true);
@@ -239,36 +277,7 @@ bool pkgSourceList::ReadAppend(string File)
       if (Parse == 0)
 	 return _error->Error(_("Type '%s' is not known on line %u in source list %s"),LineType.c_str(),CurLine,File.c_str());
       
-      // Vendor name specified
-      if (C[0] == '[')
-      {
-	 string VendorID;
-	 
-	 if (ParseQuoteWord(C,VendorID) == false)
-	     return _error->Error(_("Malformed line %u in source list %s (vendor id)"),CurLine,File.c_str());
-
-	 if (VendorID.length() < 2 || VendorID.end()[-1] != ']')
-	     return _error->Error(_("Malformed line %u in source list %s (vendor id)"),CurLine,File.c_str());
-	 VendorID = string(VendorID,1,VendorID.size()-2);
-	 
-// 	 for (vector<const Vendor *>::const_iterator iter = VendorList.begin();
-// 	      iter != VendorList.end(); iter++) 
-// 	 {
-// 	    if ((*iter)->GetVendorID() == VendorID)
-// 	    {
-// 	      if (_config->FindB("Debug::sourceList", false)) 
-// 		std::cerr << "Comparing VendorID \"" << VendorID << "\" with \"" << (*iter)->GetVendorID() << '"' << std::endl;
-// 	       Verifier = *iter;
-// 	       break;
-// 	    }
-// 	 }
-
-// 	 if (Verifier == 0)
-// 	    return _error->Error(_("Unknown vendor ID '%s' in line %u of source list %s"),
-// 				 VendorID.c_str(),CurLine,File.c_str());
-      }
-
-      if (Parse->ParseLine(SrcList,C,CurLine,File) == false)
+      if (Parse->ParseLine(SrcList, C, CurLine, File) == false)
 	 return false;
    }
    return true;

+ 5 - 3
apt-pkg/sourcelist.h

@@ -29,6 +29,7 @@
 
 #include <string>
 #include <vector>
+#include <map>
 #include <apt-pkg/pkgcache.h>
 #include <apt-pkg/metaindex.h>
 
@@ -57,9 +58,10 @@ class pkgSourceList
       bool FixupURI(string &URI) const;
       virtual bool ParseLine(vector<metaIndex *> &List,
 			     const char *Buffer,
-			     unsigned long CurLine,string File) const;
-      virtual bool CreateItem(vector<metaIndex *> &List,string URI,
-			      string Dist,string Section) const = 0;
+			     unsigned long const &CurLine,string const &File) const;
+      virtual bool CreateItem(vector<metaIndex *> &List,string const &URI,
+			      string const &Dist,string const &Section,
+			      std::map<string, string> const &Options) const = 0;
       Type();
       virtual ~Type() {};
    };

+ 2 - 11
apt-pkg/tagfile.cc

@@ -193,17 +193,8 @@ bool pkgTagFile::Jump(pkgTagSection &Tag,unsigned long Offset)
 									/*}}}*/
 // TagSection::Scan - Scan for the end of the header information	/*{{{*/
 // ---------------------------------------------------------------------
-/* This looks for the first double new line in the data stream. It also
-   indexes the tags in the section. This very simple hash function for the
-   last 8 letters gives very good performance on the debian package files */
-inline static unsigned long AlphaHash(const char *Text, const char *End = 0)
-{
-   unsigned long Res = 0;
-   for (; Text != End && *Text != ':' && *Text != 0; Text++)
-      Res = ((unsigned long)(*Text) & 0xDF) ^ (Res << 1);
-   return Res & 0xFF;
-}
-
+/* This looks for the first double new line in the data stream.
+   It also indexes the tags in the section. */
 bool pkgTagSection::Scan(const char *Start,unsigned long MaxLength)
 {
    const char *End = Start + MaxLength;

+ 14 - 1
apt-pkg/tagfile.h

@@ -33,7 +33,18 @@ class pkgTagSection
    unsigned int AlphaIndexes[0x100];
    
    unsigned int TagCount;
-     
+
+   /* This very simple hash function for the last 8 letters gives
+      very good performance on the debian package files */
+   inline static unsigned long AlphaHash(const char *Text, const char *End = 0)
+   {
+      unsigned long Res = 0;
+      for (; Text != End && *Text != ':' && *Text != 0; Text++)
+	 Res = ((unsigned long)(*Text) & 0xDF) ^ (Res << 1);
+      return Res & 0xFF;
+   }
+
+
    protected:
    const char *Stop;
 
@@ -54,6 +65,8 @@ class pkgTagSection
    virtual void TrimRecord(bool BeforeRecord, const char* &End);
    
    inline unsigned int Count() const {return TagCount;};
+   inline bool Exists(const char* const Tag) {return AlphaIndexes[AlphaHash(Tag)] != 0;}
+ 
    inline void Get(const char *&Start,const char *&Stop,unsigned int I) const
                    {Start = Section + Indexes[I]; Stop = Section + Indexes[I+1];}
 	    

+ 7 - 1
apt-pkg/versionmatch.cc

@@ -100,6 +100,8 @@ pkgVersionMatch::pkgVersionMatch(string Data,MatchType Type) : Type(Type)
 	    RelLabel = Fragments[J]+2;
 	 else if (stringcasecmp(Fragments[J],Fragments[J]+2,"c=") == 0)
 	    RelComponent = Fragments[J]+2;
+	 else if (stringcasecmp(Fragments[J],Fragments[J]+2,"b=") == 0)
+	    RelArchitecture = Fragments[J]+2;
       }
 
       if (RelVerStr.end()[-1] == '*')
@@ -178,7 +180,7 @@ bool pkgVersionMatch::FileMatch(pkgCache::PkgFileIterator File)
       if (RelVerStr.empty() == true && RelOrigin.empty() == true &&
 	  RelArchive.empty() == true && RelLabel.empty() == true &&
 	  RelRelease.empty() == true && RelCodename.empty() == true &&
-	  RelComponent.empty() == true)
+	  RelComponent.empty() == true && RelArchitecture.empty() == true)
 	 return false;
 
       if (RelVerStr.empty() == false)
@@ -211,6 +213,10 @@ bool pkgVersionMatch::FileMatch(pkgCache::PkgFileIterator File)
 	 if (File->Component == 0 ||
 	     stringcasecmp(RelComponent,File.Component()) != 0)
 	    return false;
+      if (RelArchitecture.empty() == false)
+	 if (File->Architecture == 0 ||
+	     stringcasecmp(RelArchitecture,File.Architecture()) != 0)
+	    return false;
       return true;
    }
 

+ 2 - 0
apt-pkg/versionmatch.h

@@ -23,6 +23,7 @@
       Codename (n=) e.g. etch, lenny, squeeze, sid
       Label (l=)
       Component (c=)
+      Binary Architecture (b=)
    If there are no equals signs in the string then it is scanned in short
    form - if it starts with a number it is Version otherwise it is an
    Archive or a Codename.
@@ -55,6 +56,7 @@ class pkgVersionMatch
    string RelArchive;
    string RelLabel;
    string RelComponent;
+   string RelArchitecture;
    bool MatchAll;
    
    // Origin Matching

+ 57 - 42
cmdline/apt-cache.cc

@@ -139,7 +139,7 @@ bool UnMet(CommandLine &CmdL)
 	    // Oops, it failed..
 	    if (Header == false)
 	       ioprintf(cout,_("Package %s version %s has an unmet dep:\n"),
-			P.Name(),V.VerStr());
+			P.FullName(true).c_str(),V.VerStr());
 	    Header = true;
 	    
 	    // Print out the dep type
@@ -149,7 +149,7 @@ bool UnMet(CommandLine &CmdL)
 	    Start = RealStart;
 	    do
 	    {
-	       cout << Start.TargetPkg().Name();
+	       cout << Start.TargetPkg().FullName(true);
 	       if (Start.TargetVer() != 0)
 		  cout << " (" << Start.CompType() << " " << Start.TargetVer() <<
 		  ")";
@@ -182,7 +182,7 @@ bool DumpPackage(CommandLine &CmdL)
 	 continue;
       }
 
-      cout << "Package: " << Pkg.Name() << endl;
+      cout << "Package: " << Pkg.FullName(true) << endl;
       cout << "Versions: " << endl;
       for (pkgCache::VerIterator Cur = Pkg.VersionList(); Cur.end() != true; Cur++)
       {
@@ -204,7 +204,7 @@ bool DumpPackage(CommandLine &CmdL)
       cout << "Reverse Depends: " << endl;
       for (pkgCache::DepIterator D = Pkg.RevDependsList(); D.end() != true; D++)
       {
-	 cout << "  " << D.ParentPkg().Name() << ',' << D.TargetPkg().Name();
+	 cout << "  " << D.ParentPkg().FullName(true) << ',' << D.TargetPkg().FullName(true);
 	 if (D->Version != 0)
 	    cout << ' ' << DeNull(D.TargetVer()) << endl;
 	 else
@@ -216,7 +216,7 @@ bool DumpPackage(CommandLine &CmdL)
       {
 	 cout << Cur.VerStr() << " - ";
 	 for (pkgCache::DepIterator Dep = Cur.DependsList(); Dep.end() != true; Dep++)
-	    cout << Dep.TargetPkg().Name() << " (" << (int)Dep->CompareOp << " " << DeNull(Dep.TargetVer()) << ") ";
+	    cout << Dep.TargetPkg().FullName(true) << " (" << (int)Dep->CompareOp << " " << DeNull(Dep.TargetVer()) << ") ";
 	 cout << endl;
       }      
 
@@ -225,12 +225,12 @@ bool DumpPackage(CommandLine &CmdL)
       {
 	 cout << Cur.VerStr() << " - ";
 	 for (pkgCache::PrvIterator Prv = Cur.ProvidesList(); Prv.end() != true; Prv++)
-	    cout << Prv.ParentPkg().Name() << " ";
+	    cout << Prv.ParentPkg().FullName(true) << " ";
 	 cout << endl;
       }
       cout << "Reverse Provides: " << endl;
       for (pkgCache::PrvIterator Prv = Pkg.ProvidesList(); Prv.end() != true; Prv++)
-	 cout << Prv.OwnerPkg().Name() << " " << Prv.OwnerVer().VerStr() << endl;            
+	 cout << Prv.OwnerPkg().FullName(true) << " " << Prv.OwnerVer().VerStr() << endl;
    }
 
    return true;
@@ -353,13 +353,13 @@ bool Dump(CommandLine &Cmd)
    
    for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
    {
-      cout << "Package: " << P.Name() << endl;
+      cout << "Package: " << P.FullName(true) << endl;
       for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; V++)
       {
 	 cout << " Version: " << V.VerStr() << endl;
 	 cout << "     File: " << V.FileList().File().FileName() << endl;
 	 for (pkgCache::DepIterator D = V.DependsList(); D.end() == false; D++)
-	    cout << "  Depends: " << D.TargetPkg().Name() << ' ' << 
+	    cout << "  Depends: " << D.TargetPkg().FullName(true) << ' ' << 
 	                     DeNull(D.TargetVer()) << endl;
 	 for (pkgCache::DescIterator D = V.DescriptionList(); D.end() == false; D++)
 	 {
@@ -570,11 +570,11 @@ bool Depends(CommandLine &CmdL)
 	 pkgCache::VerIterator Ver = Pkg.VersionList();
 	 if (Ver.end() == true)
 	 {
-	    cout << '<' << Pkg.Name() << '>' << endl;
+	    cout << '<' << Pkg.FullName(true) << '>' << endl;
 	    continue;
 	 }
 	 
-	 cout << Pkg.Name() << endl;
+	 cout << Pkg.FullName(true) << endl;
 	 
 	 for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; D++)
 	 {
@@ -596,9 +596,9 @@ bool Depends(CommandLine &CmdL)
 	    
 		// Show the package
 		if (Trg->VersionList == 0)
-		  cout << D.DepType() << ": <" << Trg.Name() << ">" << endl;
+		  cout << D.DepType() << ": <" << Trg.FullName(true) << ">" << endl;
 		else
-		  cout << D.DepType() << ": " << Trg.Name() << endl;
+		  cout << D.DepType() << ": " << Trg.FullName(true) << endl;
 	    
 		if (Recurse == true)
 		  Colours[D.TargetPkg()->ID]++;
@@ -614,7 +614,7 @@ bool Depends(CommandLine &CmdL)
 	       if (V != Cache.VerP + V.ParentPkg()->VersionList ||
 		   V->ParentPkg == D->Package)
 		  continue;
-	       cout << "    " << V.ParentPkg().Name() << endl;
+	       cout << "    " << V.ParentPkg().FullName(true) << endl;
 	       
 	       if (Recurse == true)
 		  Colours[D.ParentPkg()->ID]++;
@@ -663,11 +663,11 @@ bool RDepends(CommandLine &CmdL)
 	 pkgCache::VerIterator Ver = Pkg.VersionList();
 	 if (Ver.end() == true)
 	 {
-	    cout << '<' << Pkg.Name() << '>' << endl;
+	    cout << '<' << Pkg.FullName(true) << '>' << endl;
 	    continue;
 	 }
 	 
-	 cout << Pkg.Name() << endl;
+	 cout << Pkg.FullName(true) << endl;
 	 
 	 cout << "Reverse Depends:" << endl;
 	 for (pkgCache::DepIterator D = Pkg.RevDependsList(); D.end() == false; D++)
@@ -684,9 +684,9 @@ bool RDepends(CommandLine &CmdL)
 		  cout << "  ";
 
 		if (Trg->VersionList == 0)
-		  cout << D.DepType() << ": <" << Trg.Name() << ">" << endl;
+		  cout << D.DepType() << ": <" << Trg.FullName(true) << ">" << endl;
 		else
-		  cout << Trg.Name() << endl;
+		  cout << Trg.FullName(true) << endl;
 
 		if (Recurse == true)
 		  Colours[D.ParentPkg()->ID]++;
@@ -702,7 +702,7 @@ bool RDepends(CommandLine &CmdL)
 	       if (V != Cache.VerP + V.ParentPkg()->VersionList ||
 		   V->ParentPkg == D->Package)
 		  continue;
-	       cout << "    " << V.ParentPkg().Name() << endl;
+	       cout << "    " << V.ParentPkg().FullName(true) << endl;
 	       
 	       if (Recurse == true)
 		  Colours[D.ParentPkg()->ID]++;
@@ -863,7 +863,7 @@ bool XVcg(CommandLine &CmdL)
 	    // Only graph critical deps	    
 	    if (D.IsCritical() == true)
 	    {
-	       printf ("edge: { sourcename: \"%s\" targetname: \"%s\" class: 2 ",Pkg.Name(), D.TargetPkg().Name() );
+	       printf ("edge: { sourcename: \"%s\" targetname: \"%s\" class: 2 ",Pkg.FullName(true).c_str(), D.TargetPkg().FullName(true).c_str() );
 	       
 	       // Colour the node for recursion
 	       if (Show[D.TargetPkg()->ID] <= DoneNR)
@@ -922,10 +922,10 @@ bool XVcg(CommandLine &CmdL)
 	 continue;
 
       if (Show[Pkg->ID] == DoneNR)
-	 printf("node: { title: \"%s\" label: \"%s\" color: orange shape: %s }\n", Pkg.Name(), Pkg.Name(),
+	 printf("node: { title: \"%s\" label: \"%s\" color: orange shape: %s }\n", Pkg.FullName(true).c_str(), Pkg.FullName(true).c_str(),
 		Shapes[ShapeMap[Pkg->ID]]);
       else
-	printf("node: { title: \"%s\" label: \"%s\" shape: %s }\n", Pkg.Name(), Pkg.Name(), 
+	printf("node: { title: \"%s\" label: \"%s\" shape: %s }\n", Pkg.FullName(true).c_str(), Pkg.FullName(true).c_str(),
 		Shapes[ShapeMap[Pkg->ID]]);
       
    }
@@ -1084,7 +1084,7 @@ bool Dotty(CommandLine &CmdL)
 	    // Only graph critical deps	    
 	    if (D.IsCritical() == true)
 	    {
-	       printf("\"%s\" -> \"%s\"",Pkg.Name(),D.TargetPkg().Name());
+	       printf("\"%s\" -> \"%s\"",Pkg.FullName(true).c_str(),D.TargetPkg().FullName(true).c_str());
 	       
 	       // Colour the node for recursion
 	       if (Show[D.TargetPkg()->ID] <= DoneNR)
@@ -1138,10 +1138,10 @@ bool Dotty(CommandLine &CmdL)
       
       // Orange box for early recursion stoppage
       if (Show[Pkg->ID] == DoneNR)
-	 printf("\"%s\" [color=orange,shape=%s];\n",Pkg.Name(),
+	 printf("\"%s\" [color=orange,shape=%s];\n",Pkg.FullName(true).c_str(),
 		Shapes[ShapeMap[Pkg->ID]]);
       else
-	 printf("\"%s\" [shape=%s];\n",Pkg.Name(),
+	 printf("\"%s\" [shape=%s];\n",Pkg.FullName(true).c_str(),
 		Shapes[ShapeMap[Pkg->ID]]);
    }
    
@@ -1417,11 +1417,15 @@ bool ShowPackage(CommandLine &CmdL)
    
    for (const char **I = CmdL.FileList + 1; *I != 0; I++)
    {
+      // FIXME: Handle the case in which pkgname name:arch is not found
       pkgCache::PkgIterator Pkg = Cache.FindPkg(*I);
       if (Pkg.end() == true)
       {
-	 _error->Warning(_("Unable to locate package %s"),*I);
-	 continue;
+	 Pkg = Cache.FindPkg(*I, "any");
+	 if (Pkg.end() == true) {
+		_error->Warning(_("Unable to locate package %s"),*I);
+		continue;
+	 }
       }
 
       ++found;
@@ -1457,16 +1461,17 @@ bool ShowPackage(CommandLine &CmdL)
 bool ShowPkgNames(CommandLine &CmdL)
 {
    pkgCache &Cache = *GCache;
-   pkgCache::PkgIterator I = Cache.PkgBegin();
-   bool All = _config->FindB("APT::Cache::AllNames","false");
-   
+   pkgCache::GrpIterator I = Cache.GrpBegin();
+   bool const All = _config->FindB("APT::Cache::AllNames","false");
+
    if (CmdL.FileList[1] != 0)
    {
       for (;I.end() != true; I++)
       {
-	 if (All == false && I->VersionList == 0)
+	 if (All == false && I->FirstPackage == 0)
+	    continue;
+	 if (I.FindPkg("any")->VersionList == 0)
 	    continue;
-	 
 	 if (strncmp(I.Name(),CmdL.FileList[1],strlen(CmdL.FileList[1])) == 0)
 	    cout << I.Name() << endl;
       }
@@ -1477,7 +1482,9 @@ bool ShowPkgNames(CommandLine &CmdL)
    // Show all pkgs
    for (;I.end() != true; I++)
    {
-      if (All == false && I->VersionList == 0)
+      if (All == false && I->FirstPackage == 0)
+	 continue;
+      if (I.FindPkg("any")->VersionList == 0)
 	 continue;
       cout << I.Name() << endl;
    }
@@ -1565,7 +1572,7 @@ bool Policy(CommandLine &CmdL)
 	    continue;
 
 	 // Print the package name and the version we are forcing to
-	 cout << "     " << I.Name() << " -> ";
+	 cout << "     " << I.FullName(true) << " -> ";
 	 
 	 pkgCache::VerIterator V = Plcy.GetMatch(I);
 	 if (V.end() == true)
@@ -1576,19 +1583,26 @@ bool Policy(CommandLine &CmdL)
       
       return true;
    }
-   
+
+   string const myArch = _config->Find("APT::Architecture");
+
    // Print out detailed information for each package
    for (const char **I = CmdL.FileList + 1; *I != 0; I++)
    {
-      pkgCache::PkgIterator Pkg = Cache.FindPkg(*I);
+      pkgCache::GrpIterator Grp = Cache.FindGrp(*I);
+      pkgCache::PkgIterator Pkg = Grp.FindPkg("any");
       if (Pkg.end() == true)
       {
 	 _error->Warning(_("Unable to locate package %s"),*I);
 	 continue;
       }
-      
-      cout << Pkg.Name() << ":" << endl;
-      
+
+      for (; Pkg.end() != true; Pkg = Grp.NextPkg(Pkg)) {
+      if (strcmp(Pkg.Arch(),"all") == 0)
+	 continue;
+
+      cout << Pkg.FullName(true) << ":" << endl;
+
       // Installed version
       cout << _("  Installed: ");
       if (Pkg->CurrentVer == 0)
@@ -1633,8 +1647,9 @@ bool Policy(CommandLine &CmdL)
 	       return _error->Error(_("Cache is out of sync, can't x-ref a package file"));
 	    printf("       %4i %s\n",Plcy.GetPriority(VF.File()),
 		   Indx->Describe(true).c_str());
-	 }	 
-      }      
+	 }
+      }
+      }
    }
    
    return true;
@@ -1684,7 +1699,7 @@ bool Madison(CommandLine &CmdL)
                     {
                          if ((*IF)->FindInCache(*(VF.File().Cache())) == VF.File())
                          {
-                                   cout << setw(10) << Pkg.Name() << " | " << setw(10) << V.VerStr() << " | "
+                                   cout << setw(10) << Pkg.FullName(true) << " | " << setw(10) << V.VerStr() << " | "
                                         << (*IF)->Describe(true) << endl;
                          }
                     }

+ 86 - 50
cmdline/apt-get.cc

@@ -258,8 +258,8 @@ void ShowBroken(ostream &out,CacheFile &Cache,bool Now)
       }
       
       // Print out each package and the failed dependencies
-      out <<"  " <<  I.Name() << ":";
-      unsigned Indent = strlen(I.Name()) + 3;
+      out << " " << I.FullName(true) << " :";
+      unsigned const Indent = I.FullName(true).size() + 3;
       bool First = true;
       pkgCache::VerIterator Ver;
       
@@ -312,7 +312,7 @@ void ShowBroken(ostream &out,CacheFile &Cache,bool Now)
 	       out << ' ' << End.DepType() << ": ";
 	    FirstOr = false;
 	    
-	    out << Start.TargetPkg().Name();
+	    out << Start.TargetPkg().FullName(true);
 	 
 	    // Show a quick summary of the version requirements
 	    if (Start.TargetVer() != 0)
@@ -374,7 +374,9 @@ void ShowNew(ostream &out,CacheFile &Cache)
    {
       pkgCache::PkgIterator I(Cache,Cache.List[J]);
       if (Cache[I].NewInstall() == true) {
-         List += string(I.Name()) + " ";
+	 if (Cache[I].CandidateVerIter(Cache).Pseudo() == true)
+	    continue;
+         List += I.FullName(true) + " ";
          VersionsList += string(Cache[I].CandVersion) + "\n";
       }
    }
@@ -396,10 +398,12 @@ void ShowDel(ostream &out,CacheFile &Cache)
       pkgCache::PkgIterator I(Cache,Cache.List[J]);
       if (Cache[I].Delete() == true)
       {
+	 if (Cache[I].CandidateVerIter(Cache).Pseudo() == true)
+	    continue;
 	 if ((Cache[I].iFlags & pkgDepCache::Purge) == pkgDepCache::Purge)
-	    List += string(I.Name()) + "* ";
+	    List += I.FullName(true) + "* ";
 	 else
-	    List += string(I.Name()) + " ";
+	    List += I.FullName(true) + " ";
      
      VersionsList += string(Cache[I].CandVersion)+ "\n";
       }
@@ -424,7 +428,7 @@ void ShowKept(ostream &out,CacheFile &Cache)
 	  I->CurrentVer == 0 || Cache[I].Delete() == true)
 	 continue;
       
-      List += string(I.Name()) + " ";
+      List += I.FullName(true) + " ";
       VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n";
    }
    ShowList(out,_("The following packages have been kept back:"),List,VersionsList);
@@ -444,8 +448,10 @@ void ShowUpgraded(ostream &out,CacheFile &Cache)
       // Not interesting
       if (Cache[I].Upgrade() == false || Cache[I].NewInstall() == true)
 	 continue;
-      
-      List += string(I.Name()) + " ";
+      if (Cache[I].CandidateVerIter(Cache).Pseudo() == true)
+	 continue;
+
+      List += I.FullName(true) + " ";
       VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n";
    }
    ShowList(out,_("The following packages will be upgraded:"),List,VersionsList);
@@ -465,8 +471,10 @@ bool ShowDowngraded(ostream &out,CacheFile &Cache)
       // Not interesting
       if (Cache[I].Downgrade() == false || Cache[I].NewInstall() == true)
 	 continue;
-      
-      List += string(I.Name()) + " ";
+      if (Cache[I].CandidateVerIter(Cache).Pseudo() == true)
+	 continue;
+
+      List += I.FullName(true) + " ";
       VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n";
    }
    return ShowList(out,_("The following packages will be DOWNGRADED:"),List,VersionsList);
@@ -484,7 +492,7 @@ bool ShowHold(ostream &out,CacheFile &Cache)
       pkgCache::PkgIterator I(Cache,Cache.List[J]);
       if (Cache[I].InstallVer != (pkgCache::Version *)I.CurrentVer() &&
           I->SelectedState == pkgCache::State::Hold) {
-         List += string(I.Name()) + " ";
+         List += I.FullName(true) + " ";
 		 VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n";
       }
    }
@@ -518,7 +526,7 @@ bool ShowEssential(ostream &out,CacheFile &Cache)
 	 if (Added[I->ID] == false)
 	 {
 	    Added[I->ID] = true;
-	    List += string(I.Name()) + " ";
+	    List += I.FullName(true) + " ";
         //VersionsList += string(Cache[I].CurVersion) + "\n"; ???
 	 }
       }
@@ -542,7 +550,7 @@ bool ShowEssential(ostream &out,CacheFile &Cache)
 	    Added[P->ID] = true;
 	    
 	    char S[300];
-	    snprintf(S,sizeof(S),_("%s (due to %s) "),P.Name(),I.Name());
+	    snprintf(S,sizeof(S),_("%s (due to %s) "),P.FullName(true).c_str(),I.FullName(true).c_str());
 	    List += S;
         //VersionsList += "\n"; ???
 	 }	 
@@ -566,6 +574,9 @@ void Stats(ostream &out,pkgDepCache &Dep)
    unsigned long ReInstall = 0;
    for (pkgCache::PkgIterator I = Dep.PkgBegin(); I.end() == false; I++)
    {
+      if (pkgCache::VerIterator(Dep, Dep[I].CandidateVer).Pseudo() == true)
+	 continue;
+
       if (Dep[I].NewInstall() == true)
 	 Install++;
       else
@@ -1084,7 +1095,7 @@ bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache,
       if (found_one == true)
       {
 	 ioprintf(c1out,_("Note, selecting %s instead of %s\n"),
-		  Prov.Name(),Pkg.Name());
+		  Prov.FullName(true).c_str(),Pkg.FullName(true).c_str());
 	 Pkg = Prov;
       }
    }
@@ -1095,10 +1106,20 @@ bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache,
    {
       if (AllowFail == true)
 	 ioprintf(c1out,_("Skipping %s, it is already installed and upgrade is not set.\n"),
+		  Pkg.FullName(true).c_str());
+      return true;
+   }
+
+   // Ignore request for install if package would be new
+   if (_config->FindB("APT::Get::Only-Upgrade", false) == true &&
+       Pkg->CurrentVer == 0)
+   {
+      if (AllowFail == true)
+	 ioprintf(c1out,_("Skipping %s, it is not installed and only upgrades are requested.\n"),
 		  Pkg.Name());
       return true;
    }
-   
+
    // Check if there is something at all to install
    pkgDepCache::StateCache &State = Cache[Pkg];
    if (Remove == true && Pkg->CurrentVer == 0)
@@ -1112,7 +1133,7 @@ bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache,
       if (AllowFail == false)
 	 return false;
       
-      ioprintf(c1out,_("Package %s is not installed, so not removed\n"),Pkg.Name());
+      ioprintf(c1out,_("Package %s is not installed, so not removed\n"),Pkg.FullName(true).c_str());
       return true;
    }
    
@@ -1124,7 +1145,7 @@ bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache,
       if (Pkg->ProvidesList != 0)
       {
 	 ioprintf(c1out,_("Package %s is a virtual package provided by:\n"),
-		  Pkg.Name());
+		  Pkg.FullName(true).c_str());
 	 
 	 pkgCache::PrvIterator I = Pkg.ProvidesList();
 	 for (; I.end() == false; I++)
@@ -1134,10 +1155,10 @@ bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache,
 	    if (Cache[Pkg].CandidateVerIter(Cache) == I.OwnerVer())
 	    {
 	       if (Cache[Pkg].Install() == true && Cache[Pkg].NewInstall() == false)
-		  c1out << "  " << Pkg.Name() << " " << I.OwnerVer().VerStr() <<
+		  c1out << "  " << Pkg.FullName(true) << " " << I.OwnerVer().VerStr() <<
 		  _(" [Installed]") << endl;
 	       else
-		  c1out << "  " << Pkg.Name() << " " << I.OwnerVer().VerStr() << endl;
+		  c1out << "  " << Pkg.FullName(true) << " " << I.OwnerVer().VerStr() << endl;
 	    }      
 	 }
 	 c1out << _("You should explicitly select one to install.") << endl;
@@ -1147,7 +1168,7 @@ bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache,
 	 ioprintf(c1out,
 	 _("Package %s is not available, but is referred to by another package.\n"
 	   "This may mean that the package is missing, has been obsoleted, or\n"
-           "is only available from another source\n"),Pkg.Name());
+           "is only available from another source\n"),Pkg.FullName(true).c_str());
 	 
 	 string List;
 	 string VersionsList;
@@ -1161,13 +1182,13 @@ bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache,
 	    if (Seen[Dep.ParentPkg()->ID] == true)
 	       continue;
 	    Seen[Dep.ParentPkg()->ID] = true;
-	    List += string(Dep.ParentPkg().Name()) + " ";
+	    List += Dep.ParentPkg().FullName(true) + " ";
         //VersionsList += string(Dep.ParentPkg().CurVersion) + "\n"; ???
 	 }	    
 	 ShowList(c1out,_("However the following packages replace it:"),List,VersionsList);
       }
       
-      _error->Error(_("Package %s has no installation candidate"),Pkg.Name());
+      _error->Error(_("Package %s has no installation candidate"),Pkg.FullName(true).c_str());
       return false;
    }
 
@@ -1188,7 +1209,7 @@ bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache,
       {
 	 if (Pkg->CurrentVer == 0 || Pkg.CurrentVer().Downloadable() == false)
 	    ioprintf(c1out,_("Reinstallation of %s is not possible, it cannot be downloaded.\n"),
-		     Pkg.Name());
+		     Pkg.FullName(true).c_str());
 	 else
 	    Cache.SetReInstall(Pkg,true);
       }      
@@ -1196,7 +1217,7 @@ bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache,
       {
 	 if (AllowFail == true)
 	    ioprintf(c1out,_("%s is already the newest version.\n"),
-		     Pkg.Name());
+		     Pkg.FullName(true).c_str());
       }      
    }   
    else
@@ -1225,15 +1246,15 @@ bool TryToChangeVer(pkgCache::PkgIterator Pkg,pkgDepCache &Cache,
    {
       if (IsRel == true)
 	 return _error->Error(_("Release '%s' for '%s' was not found"),
-			      VerTag,Pkg.Name());
+			      VerTag,Pkg.FullName(true).c_str());
       return _error->Error(_("Version '%s' for '%s' was not found"),
-			   VerTag,Pkg.Name());
+			   VerTag,Pkg.FullName(true).c_str());
    }
    
    if (strcmp(VerTag,Ver.VerStr()) != 0)
    {
       ioprintf(c1out,_("Selected version %s (%s) for %s\n"),
-	       Ver.VerStr(),Ver.RelStr().c_str(),Pkg.Name());
+	       Ver.VerStr(),Ver.RelStr().c_str(),Pkg.FullName(true).c_str());
    }
    
    Cache.SetCandidateVersion(Ver);
@@ -1270,12 +1291,26 @@ pkgSrcRecords::Parser *FindSrc(const char *Name,pkgRecords &Recs,
    {
       if(VerTag.empty() == false || DefRel.empty() == false) 
       {
+	 bool fuzzy = false;
 	 // we have a default release, try to locate the pkg. we do it like
 	 // this because GetCandidateVer() will not "downgrade", that means
 	 // "apt-get source -t stable apt" won't work on a unstable system
-	 for (pkgCache::VerIterator Ver = Pkg.VersionList();
-	      Ver.end() == false; Ver++) 
+	 for (pkgCache::VerIterator Ver = Pkg.VersionList();; Ver++)
 	 {
+	    // try first only exact matches, later fuzzy matches
+	    if (Ver.end() == true)
+	    {
+	       if (fuzzy == true)
+		  break;
+	       fuzzy = true;
+	       Ver = Pkg.VersionList();
+	    }
+	    // We match against a concrete version (or a part of this version)
+	    if (VerTag.empty() == false &&
+		(fuzzy == true || Cache.VS().CmpVersion(VerTag, Ver.VerStr()) != 0) && // exact match
+		(fuzzy == false || strncmp(VerTag.c_str(), Ver.VerStr(), VerTag.size()) != 0)) // fuzzy match
+	       continue;
+
 	    for (pkgCache::VerFileIterator VF = Ver.FileList();
 		 VF.end() == false; VF++) 
 	    {
@@ -1288,10 +1323,6 @@ pkgSrcRecords::Parser *FindSrc(const char *Name,pkgRecords &Recs,
 		   pkgCache::Flag::NotSource && Pkg.CurrentVer() != Ver)
 		  continue;
 
-	       // We match against a concrete version (or a part of this version)
-	       if (VerTag.empty() == false && strncmp(VerTag.c_str(), Ver.VerStr(), VerTag.size()) != 0)
-		  continue;
-
 	       // or we match against a release
 	       if(VerTag.empty() == false ||
 		  (VF.File().Archive() != 0 && VF.File().Archive() == DefRel) ||
@@ -1302,10 +1333,9 @@ pkgSrcRecords::Parser *FindSrc(const char *Name,pkgRecords &Recs,
 		  // no SourcePkg name, so it is the "binary" name
 		  if (Src.empty() == true)
 		     Src = TmpSrc;
-		  // no Version, so we try the Version of the SourcePkg -
-		  // and after that the version of the binary package
-		  if (VerTag.empty() == true)
-		     VerTag = Parse.SourceVer();
+		  // the Version we have is possibly fuzzy or includes binUploads,
+		  // so we use the Version of the SourcePkg (empty if same as package)
+		  VerTag = Parse.SourceVer();
 		  if (VerTag.empty() == true)
 		     VerTag = Ver.VerStr();
 		  break;
@@ -1371,7 +1401,8 @@ pkgSrcRecords::Parser *FindSrc(const char *Name,pkgRecords &Recs,
 	 const string Ver = Parse->Version();
 
 	 // Ignore all versions which doesn't fit
-	 if (VerTag.empty() == false && strncmp(VerTag.c_str(), Ver.c_str(), VerTag.size()) != 0)
+	 if (VerTag.empty() == false &&
+	     Cache.VS().CmpVersion(VerTag, Ver) != 0) // exact match
 	    continue;
 
 	 // Newer version or an exact match? Save the hit
@@ -1491,7 +1522,7 @@ bool DoAutomaticRemove(CacheFile &Cache)
       {
 	 if(Pkg.CurrentVer() != 0 || Cache[Pkg].Install())
 	    if(Debug)
-	       std::cout << "We could delete %s" <<  Pkg.Name() << std::endl;
+	       std::cout << "We could delete %s" <<  Pkg.FullName(true).c_str() << std::endl;
 
 	 if (doAutoRemove)
 	 {
@@ -1510,7 +1541,7 @@ bool DoAutomaticRemove(CacheFile &Cache)
 	       // we don't need to fill the strings if we don't need them
 	       if (smallList == false)
 	       {
-		 autoremovelist += string(Pkg.Name()) + " ";
+		 autoremovelist += Pkg.FullName(true) + " ";
 		 autoremoveversions += string(Cache[Pkg].CandVersion) + "\n";
 	       }
 	    }
@@ -1781,10 +1812,11 @@ bool DoInstall(CommandLine &CmdL)
 	       Cache[Pkg].Install() == false && 
 	       (Cache[Pkg].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.Name());
+			Pkg.FullName(true).c_str());
 	       Cache->MarkAuto(Pkg,false);
 	       AutoMarkChanged++;
 	    }
@@ -1853,7 +1885,7 @@ bool DoInstall(CommandLine &CmdL)
 		break;
 	 
 	 if (*J == 0) {
-	    List += string(I.Name()) + " ";
+	    List += I.FullName(true) + " ";
 	    VersionsList += string(Cache[I].CandVersion) + "\n";
 	 }
       }
@@ -1889,7 +1921,7 @@ bool DoInstall(CommandLine &CmdL)
 	    for(;;)
 	    {
 	       /* Skip if package is  installed already, or is about to be */
-	       string target = string(Start.TargetPkg().Name()) + " ";
+	       string target = Start.TargetPkg().FullName(true) + " ";
 	       
 	       if ((*Start.TargetPkg()).SelectedState == pkgCache::State::Install
 		   || Cache[Start.TargetPkg()].Install())
@@ -2290,6 +2322,7 @@ bool DoSource(CommandLine &CmdL)
    {
       for (unsigned I = 0; I != J; I++)
 	 ioprintf(cout,_("Fetch source %s\n"),Dsc[I].Package.c_str());
+      delete[] Dsc;
       return true;
    }
    
@@ -2300,6 +2333,7 @@ bool DoSource(CommandLine &CmdL)
       for (; I != Fetcher.UriEnd(); I++)
 	 cout << '\'' << I->URI << "' " << flNotDir(I->Owner->DestFile) << ' ' << 
 	       I->Owner->FileSize << ' ' << I->Owner->HashSum() << endl;
+      delete[] Dsc;
       return true;
    }
    
@@ -2325,6 +2359,7 @@ bool DoSource(CommandLine &CmdL)
    if (_config->FindB("APT::Get::Download-only",false) == true)
    {
       c1out << _("Download complete and in download only mode") << endl;
+      delete[] Dsc;
       return true;
    }
 
@@ -2386,7 +2421,8 @@ bool DoSource(CommandLine &CmdL)
       
       _exit(0);
    }
-   
+   delete[] Dsc;
+
    // Wait for the subprocess
    int Status = 0;
    while (waitpid(Process,&Status,0) != Process)
@@ -2440,7 +2476,7 @@ bool DoBuildDep(CommandLine &CmdL)
             
       // Process the build-dependencies
       vector<pkgSrcRecords::Parser::BuildDepRec> BuildDeps;
-      if (Last->BuildDepends(BuildDeps, _config->FindB("APT::Get::Arch-Only",false)) == false)
+      if (Last->BuildDepends(BuildDeps, _config->FindB("APT::Get::Arch-Only",true)) == false)
       	return _error->Error(_("Unable to get build-dependency information for %s"),Src.c_str());
    
       // Also ensure that build-essential packages are present
@@ -2539,7 +2575,7 @@ bool DoBuildDep(CommandLine &CmdL)
             for (; Prv.end() != true; Prv++)
 	    {
                if (_config->FindB("Debug::BuildDeps",false) == true)
-                    cout << "  Checking provider " << Prv.OwnerPkg().Name() << endl;
+                    cout << "  Checking provider " << Prv.OwnerPkg().FullName() << endl;
 
 	       if ((*Cache)[Prv.OwnerPkg()].InstVerIter(*Cache).end() == false)
 	          break;
@@ -2580,7 +2616,7 @@ bool DoBuildDep(CommandLine &CmdL)
                if (Prv.end() == false)
                {
                   if (_config->FindB("Debug::BuildDeps",false) == true)
-                     cout << "  Is provided by installed package " << Prv.OwnerPkg().Name() << endl;
+                     cout << "  Is provided by installed package " << Prv.OwnerPkg().FullName() << endl;
                   skipAlternatives = hasAlternatives;
                   continue;
                }
@@ -2605,7 +2641,7 @@ bool DoBuildDep(CommandLine &CmdL)
                   return _error->Error(_("Failed to satisfy %s dependency for %s: Installed package %s is too new"),
                                        Last->BuildDepType((*D).Type),
                                        Src.c_str(),
-                                       Pkg.Name());
+                                       Pkg.FullName(true).c_str());
                }
             }
 
@@ -2654,7 +2690,6 @@ bool DoBuildDep(CommandLine &CmdL)
    return true;
 }
 									/*}}}*/
-
 // DoMoo - Never Ask, Never Tell					/*{{{*/
 // ---------------------------------------------------------------------
 /* */
@@ -2823,6 +2858,7 @@ int main(int argc,const char *argv[])					/*{{{*/
       {0,"fix-missing","APT::Get::Fix-Missing",0},
       {0,"ignore-hold","APT::Ignore-Hold",0},      
       {0,"upgrade","APT::Get::upgrade",0},
+      {0,"only-upgrade","APT::Get::Only-Upgrade",0},
       {0,"force-yes","APT::Get::force-yes",0},
       {0,"print-uris","APT::Get::Print-URIs",0},
       {0,"diff-only","APT::Get::Diff-Only",0},

+ 4 - 0
cmdline/apt-mark

@@ -76,6 +76,10 @@ if __name__ == "__main__":
                       help="print verbose status messages to stdout")
     (options, args) = parser.parse_args()
 
+    if not args:
+        parser.print_help()
+        sys.exit(1)
+
     # get the state-file
     if not options.filename:
         STATE_FILE = apt_pkg.config.find_dir("Dir::State") + "extended_states"

+ 2 - 1
debian/apt-doc.docs

@@ -1 +1,2 @@
-README.progress-reporting
+README.progress-reporting
+README.MultiArch

+ 62 - 0
debian/changelog

@@ -8,6 +8,68 @@ apt (0.7.26~exp3) UNRELEASED; urgency=low
   * Add "manpages-pl (<< 20060617-3~)" to avoid file conflicts with
     that package that was providing some manpages for APT utilities.
 
+  [ David Kalnischkies ]
+  * [BREAK] merge MultiArch-ABI. We don't support MultiArch,
+    but we support the usage of the new ABI so libapt users
+    can start to prepare for MultiArch (Closes: #536029)
+  * Ignore :qualifiers after package name in build dependencies
+    in the library by default, but try to honour them in apt-get
+    as we have some sort of MultiArch support ready (Closes: #558103)
+  * add translation of the manpages to PT (portuguese)
+    Thanks to Américo Monteiro!
+  * Switch to dpkg-source 3.0 (native) format
+  * apt-pkg/depcache.cc:
+    - remove Auto-Installed information from extended_states
+      together with the package itself (Closes: #572364)
+  * cmdline/apt-mark:
+    - don't crash if no arguments are given (Closes: #570962)
+  * debian/control:
+    - remove some years old and obsolete Replaces
+    - add automake/conf build-depends/conflicts as recommend by
+      the autotools-dev README (Closes: #572615)
+  * apt-pkg/contrib/mmap.{h,cc}:
+    - add char[] fallback for filesystems without shared writable
+      mmap() like JFFS2. Thanks to Marius Vollmer for writing
+      and to Loïc Minier for pointing to the patch! (Closes: #314334)
+  * doc/apt_preferences.5.xml:
+    - fix two typos and be more verbose in the novice warning.
+      Thanks to Osamu Aoki for pointing it out! (Closes: #567669)
+    - fix a=sid vs. n=sid typo, thanks Ansgar Burchardt!
+    - origin can be used to match a hostname (Closes: #352667)
+    - remove wrong pin-priority is optional remark (Closes: #574944)
+  * apt-pkg/deb/dpkgpm.cc:
+    - fix error message construction in OpenLog()
+    - if available store the Commandline in the history
+  * cmdline/apt-get.cc:
+    - add a --only-upgrade flag to install command (Closes: #572259)
+    - fix memory leaks in error conditions in DoSource()
+    - try version match in FindSrc first exact than fuzzy (LP: #551178)
+  * apt-pkg/contrib/cmndline.cc:
+    - save Commandline in Commandline::AsString for logging
+  * apt-pkg/deb/debversion.cc:
+    - consider absent of debian revision equivalent to 0 (Closes: #573592)
+  * doc/makefile, doc/*:
+    - generate subdirectories for building the manpages in on the fly
+      depending on the po files we have.
+  * apt-pkg/pkgcachegen.cc:
+    - merge versions correctly even if multiple different versions
+      with the same version number are available.
+      Thanks to Magnus Holmgren for the patch! (Closes: #351056)
+  * ftparchive/writer.cc:
+    - write LongDescriptions if they shouldn't be included in Packages
+      file into i18n/Translation-en by default.
+  * doc/po/de.po:
+    - correct a few typos in the german manpage translation.
+      Thanks to Chris Leick and Georg Koppen! (Closes: #574962)
+  * apt-pkg/contrib/strutl.cc:
+    - convert all toupper calls to tolower_ascii for a little speedup
+
+  [ Jean-Baptiste Lallement ]
+  * apt-pkg/contrib/strutl.cc:
+    - always escape '%' (LP: #130289) (Closes: #500560)
+    - unescape '%' sequence only if followed by 2 hex digit
+    - username/password are urlencoded in proxy string (RFC 3986)
+
   [ Julian Andres Klode ]
   * cmdline/apt-cache.cc:
     - Change behavior of showsrc to match the one of show (Closes: #512046).

+ 3 - 4
debian/control

@@ -6,13 +6,14 @@ Uploaders: Michael Vogt <mvo@debian.org>, Otavio Salvador <otavio@debian.org>,
  Christian Perrier <bubulle@debian.org>, Daniel Burrows <dburrows@debian.org>,
  Luca Bruno <lethalman88@gmail.com>, Julian Andres Klode <jak@debian.org>
 Standards-Version: 3.8.4
-Build-Depends: debhelper (>= 5.0), libdb-dev, gettext (>= 0.12), libcurl4-gnutls-dev | libcurl3-gnutls-dev (>= 7.15.5), debiandoc-sgml, xsltproc, docbook-xsl, po4a (>= 0.34-2), autotools-dev
+Build-Depends: debhelper (>= 5.0), libdb-dev, gettext (>= 0.12), libcurl4-gnutls-dev | libcurl3-gnutls-dev (>= 7.15.5), debiandoc-sgml, xsltproc, docbook-xsl, po4a (>= 0.34-2), autotools-dev, autoconf, automake
+Build-Conflicts: autoconf2.13, automake1.4
 Vcs-Bzr: http://bzr.debian.org/apt/debian-sid/
 
 Package: apt
 Architecture: any
 Depends: ${shlibs:Depends}, debian-archive-keyring, ${misc:Depends}
-Replaces: libapt-pkg-doc (<< 0.3.7), libapt-pkg-dev (<< 0.3.7), manpages-pl (<< 20060617-3~)
+Replaces: manpages-pl (<< 20060617-3~)
 Provides: ${libapt-pkg:provides}
 Conflicts: python-apt (<< 0.7.93.2~)
 Suggests: aptitude | synaptic | wajig, dpkg-dev, apt-doc, bzip2, lzma, python-apt
@@ -28,7 +29,6 @@ Package: apt-doc
 Architecture: all
 Priority: optional
 Depends: ${misc:Depends}
-Replaces: apt (<< 0.5.4.9)
 Section: doc
 Description: Documentation for APT
  This package contains the user guide and offline guide, for APT, an
@@ -57,7 +57,6 @@ Package: apt-utils
 Architecture: any
 Depends: ${shlibs:Depends}, ${misc:Depends}
 Provides: ${libapt-inst:provides}
-Replaces: apt (<< 0.5.9)
 Description: APT utility programs
  This package contains some APT utility programs such as apt-ftparchive,
  apt-sortpkgs and apt-extracttemplates.

+ 1 - 0
debian/source/format

@@ -0,0 +1 @@
+3.0 (native)

+ 30 - 5
doc/apt-ftparchive.1.xml

@@ -224,7 +224,13 @@
       This is similar to <literal>Packages::Compress</literal> 
       except that it controls the compression for the Contents files.</para></listitem>
       </varlistentry>
-      
+
+      <varlistentry><term>Translation::Compress</term>
+      <listitem><para>
+      This is similar to <literal>Packages::Compress</literal> 
+      except that it controls the compression for the Translation-en master file.</para></listitem>
+      </varlistentry>
+
       <varlistentry><term>DeLinkLimit</term>
       <listitem><para>
       Specifies the number of kilobytes to delink (and 
@@ -238,6 +244,12 @@
       defaults to 0644. All index files are set to this mode with no regard 
       to the umask.</para></listitem>
       </varlistentry>
+
+      <varlistentry><term>LongDescription</term>
+      <listitem><para>
+      Sets if long descriptions should be included in the Packages file or split
+      out into a master Translation-en file.</para></listitem>
+      </varlistentry>
      </variablelist>
    </refsect2>
    
@@ -289,7 +301,14 @@
       Sets the output Sources file. Defaults to 
       <filename>$(DIST)/$(SECTION)/source/Sources</filename></para></listitem>
       </varlistentry>
-      
+
+      <varlistentry><term>Translation</term>
+      <listitem><para>
+      Set the output Translation-en master file with the long descriptions if they
+      should be not included in the Packages file. Defaults to
+      <filename>$(DIST)/$(SECTION)/i18n/Translation-en</filename></para></listitem>
+      </varlistentry>
+
       <varlistentry><term>InternalPrefix</term>
       <listitem><para>
       Sets the path prefix that causes a symlink to be
@@ -371,7 +390,13 @@ for i in Sections do
       architectures that appear under search section. The special architecture 
       'source' is used to indicate that this tree has a source archive.</para></listitem>
       </varlistentry>
-      
+
+      <varlistentry><term>LongDescription</term>
+      <listitem><para>
+      Sets if long descriptions should be included in the Packages file or split
+      out into a master Translation-en file.</para></listitem>
+      </varlistentry>
+
       <varlistentry><term>BinOverride</term>
       <listitem><para>
       Sets the binary override file. The override file 
@@ -568,8 +593,8 @@ for i in Sections do
      <listitem><para>
      This configuration option defaults to "<literal>true</literal>" and should only be set to
      <literal>"false"</literal> if the Archive generated with &apt-ftparchive; also provides
-     <filename>Translation</filename> files. Note that it is currently not possible to create these
-     files with <command>apt-ftparchive</command>.
+     <filename>Translation</filename> files. Note that the <filename>Translation-en</filename>
+     master file can only be created in the generate command.
      </para></listitem>
      </varlistentry>
 

+ 7 - 0
doc/apt-get.8.xml

@@ -444,6 +444,13 @@
      Configuration Item: <literal>APT::Get::Upgrade</literal>.</para></listitem>
      </varlistentry>
 
+     <varlistentry><term><option>--only-upgrade</option></term>
+     <listitem><para>Do not install new packages; When used in conjunction with <literal>install</literal>,
+     <literal>only-upgrade</literal> will prevent packages on the command line
+     from being upgraded if they are not already installed.
+     Configuration Item: <literal>APT::Get::Only-Upgrade</literal>.</para></listitem>
+     </varlistentry>
+
      <varlistentry><term><option>--force-yes</option></term>
      <listitem><para>Force yes; This is a dangerous option that will cause apt to continue 
      without prompting if it is doing something potentially harmful. It 

+ 7 - 2
doc/apt.ent

@@ -367,9 +367,11 @@
      </varlistentry>
 ">
 
+<!-- TRANSLATOR: This is the section header for the following paragraphs - comparable
+     to the other headers like NAME and DESCRIPTION and should therefore be uppercase. -->
 <!ENTITY translation-title "TRANSLATION">
 
-<!-- TRANSLATOR: This is a placeholder. You should write here who has constributed
+<!-- TRANSLATOR: This is a placeholder. You should write here who has contributed
      to the translation in the past, who is responsible now and maybe further information
      specially related to your translation. -->
 <!ENTITY translation-holder "
@@ -379,7 +381,10 @@
 ">
 
 <!-- TRANSLATOR: As a translation is allowed to have 20% of untranslated/fuzzy strings
-     in a shipped manpage will maybe appear english parts. -->
+     in a shipped manpage newer/modified paragraphs will maybe appear in english in
+     the generated manpage. This sentence is therefore here to tell the reader that this
+     is not a mistake by the translator - obviously the target is that at least for stable
+     releases this sentence is not needed. :) -->
 <!ENTITY translation-english "
      Note that this translated document may contain untranslated parts.
      This is done on purpose, to avoid losing content when the

+ 13 - 7
doc/apt_preferences.5.xml

@@ -59,6 +59,9 @@ APT will not questioning the preferences so wrong settings will therefore
 lead to uninstallable packages or wrong decisions while upgrading packages.
 Even more problems will arise if multiply distribution releases are mixed
 without a good understanding of the following paragraphs.
+Packages included in a specific release aren't tested in and
+therefore doesn't always work as expected in older or newer releases or
+together with other packages from different releases.
 You have been warned.</para>
 
 <para>Note that the files in the <filename>/etc/apt/preferences.d</filename>
@@ -192,8 +195,15 @@ Pin: origin ""
 Pin-Priority: 999
 </programlisting>
 
-<simpara>A note of caution: the keyword used here is "<literal>origin</literal>".
-This should not be confused with the Origin of a distribution as
+<simpara>A note of caution: the keyword used here is "<literal>origin</literal>"
+which can be used to match a hostname. The following record will assign a high priority
+to all versions available from the server identified by the hostname "ftp.de.debian.org"</simpara>
+<programlisting>
+Package: *
+Pin: origin "ftp.de.debian.org"
+Pin-Priority: 999
+</programlisting>
+<simpara>This should <emphasis>not</emphasis> be confused with the Origin of a distribution as
 specified in a <filename>Release</filename> file.  What follows the "Origin:" tag
 in a <filename>Release</filename> file is not an Internet address
 but an author or vendor name, such as "Debian" or "Ximian".</simpara>
@@ -466,10 +476,6 @@ distribution.</para>
 <para>Each record in the APT preferences file can optionally begin with
 one or more lines beginning with the word <literal>Explanation:</literal>.
 This provides a place for comments.</para>
-
-<para>The <literal>Pin-Priority:</literal> line in each APT preferences record is
-optional.  If omitted, APT assigns a priority of 1 less than the last value
-specified on a line beginning with <literal>Pin-Priority: release ...</literal>.</para>
 </refsect2>
 </refsect1>
 
@@ -591,7 +597,7 @@ Pin-Priority: 900
 
 Explanation: Debian unstable is always codenamed with sid
 Package: *
-Pin: release a=sid
+Pin: release n=sid
 Pin-Priority: 800
 
 Package: *

+ 0 - 11
doc/es/makefile

@@ -1,11 +0,0 @@
-# -*- make -*-
-BASE=../..
-SUBDIR=doc/es
-
-# Bring in the default rules
-include ../../buildlib/defaults.mak
-
-# Language Code of this translation
-LC=es
-
-include $(PO4A_MANPAGE_H)

+ 2 - 0
doc/examples/configure-index

@@ -433,6 +433,8 @@ Debug
   
 }
 
+pkgCacheGen::Essential "native"; // other modes: all, none, installed
+
 /* Whatever you do, do not use this configuration file!! Take out ONLY
    the portions you need! */
 This Is Not A Valid Config File

+ 0 - 11
doc/fr/makefile

@@ -1,11 +0,0 @@
-# -*- make -*-
-BASE=../..
-SUBDIR=doc/fr
-
-# Bring in the default rules
-include ../../buildlib/defaults.mak
-
-# Language Code of this translation
-LC=fr
-
-include $(PO4A_MANPAGE_H)

+ 0 - 11
doc/it/makefile

@@ -1,11 +0,0 @@
-# -*- make -*-
-BASE=../..
-SUBDIR=doc/it
-
-# Bring in the default rules
-include ../../buildlib/defaults.mak
-
-# Language Code of this translation
-LC=it
-
-include $(PO4A_MANPAGE_H)

+ 0 - 11
doc/ja/makefile

@@ -1,11 +0,0 @@
-# -*- make -*-
-BASE=../..
-SUBDIR=doc/ja
-
-# Bring in the default rules
-include ../../buildlib/defaults.mak
-
-# Language Code of this translation
-LC=ja
-
-include $(PO4A_MANPAGE_H)

+ 2 - 2
doc/de/makefile

@@ -1,11 +1,11 @@
 # -*- make -*-
 BASE=../..
-SUBDIR=doc/de
+SUBDIR=doc/@@LANG@@
 
 # Bring in the default rules
 include ../../buildlib/defaults.mak
 
 # Language Code of this translation
-LC=de
+LC=@@LANG@@
 
 include $(PO4A_MANPAGE_H)

+ 11 - 5
doc/makefile

@@ -46,10 +46,12 @@ TO = $(DOC)
 TARGET = binary
 include $(COPY_H)
 
-#.PHONY: headers library clean veryclean all binary program doc doc.pt_BR doc.fr
+.PHONY: clean clean-subdirs veryclean veryclean-subdirs all binary doc
 doc:
-	for dir in $(SUBDIRS); do\
-		$(MAKE) -C $$dir $@; \
+	for i in $(shell ls po/*.po | sed -r 's#po/([a-z]+[A-Z_]*).po#\1#'); do \
+		test -d $$i || mkdir $$i; \
+		test -f $$i/makefile || sed "s#@@LANG@@#$$i#" lang.makefile > $$i/makefile; \
+		$(MAKE) -C $$i $@; \
 	done
 
 clean: clean-subdirs
@@ -62,7 +64,7 @@ clean-subdirs:
 
 veryclean-subdirs:
 	for dir in $(SUBDIRS); do\
-		$(MAKE) -C $$dir veryclean; \
+		rm -rf $$dir; \
 	done
 
 ifdef PO4A
@@ -70,7 +72,7 @@ doc: po4a
 
 clean: po4a-clean
 
-.PHONY: update-po po4a
+.PHONY: update-po po4a stats
 update-po:
 	po4a --previous --no-backups --force --no-translations po4a.conf
 
@@ -79,6 +81,10 @@ po4a-clean:
 
 po4a:
 	po4a --previous --no-backups po4a.conf
+
+stats:
+	for i in po/*.po; do echo -n "$$i: "; msgfmt --statistics $$i; done
+
 endif
 
 ifdef DOXYGEN

+ 0 - 11
doc/pl/makefile

@@ -1,11 +0,0 @@
-# -*- make -*-
-BASE=../..
-SUBDIR=doc/pl
-
-# Bring in the default rules
-include ../../buildlib/defaults.mak
-
-# Language Code of this translation
-LC=pl
-
-include $(PO4A_MANPAGE_H)

Datei-Diff unterdrückt, da er zu groß ist
+ 184 - 155
doc/po/apt-doc.pot


Datei-Diff unterdrückt, da er zu groß ist
+ 218 - 205
doc/po/de.po


Datei-Diff unterdrückt, da er zu groß ist
+ 199 - 162
doc/po/es.po


Datei-Diff unterdrückt, da er zu groß ist
+ 192 - 156
doc/po/fr.po


Datei-Diff unterdrückt, da er zu groß ist
+ 182 - 158
doc/po/it.po


Datei-Diff unterdrückt, da er zu groß ist
+ 195 - 159
doc/po/ja.po


Datei-Diff unterdrückt, da er zu groß ist
+ 196 - 164
doc/po/pl.po


Datei-Diff unterdrückt, da er zu groß ist
+ 11096 - 0
doc/po/pt.po


Datei-Diff unterdrückt, da er zu groß ist
+ 184 - 161
doc/po/pt_BR.po


+ 0 - 11
doc/pt_BR/makefile

@@ -1,11 +0,0 @@
-# -*- make -*-
-BASE=../..
-SUBDIR=doc/pt_BR
-
-# Bring in the default rules
-include ../../buildlib/defaults.mak
-
-# Language Code of this translation
-LC=pt_BR
-
-include $(PO4A_MANPAGE_H)

+ 52 - 11
ftparchive/apt-ftparchive.cc

@@ -63,6 +63,10 @@ struct PackageMap
    string SrcOverride;
    string SrcExtraOverride;
 
+   // Translation master file
+   bool LongDesc;
+   TranslationWriter *TransWriter;
+
    // Contents 
    string Contents;
    string ContentsHead;
@@ -101,8 +105,9 @@ struct PackageMap
 		    vector<PackageMap>::iterator End,
 		    unsigned long &Left);
    
-   PackageMap() : DeLinkLimit(0), Permissions(1), ContentsDone(false), 
-        PkgDone(false), SrcDone(false), ContentsMTime(0) {};
+   PackageMap() : LongDesc(true), TransWriter(NULL), DeLinkLimit(0), Permissions(1),
+		  ContentsDone(false), PkgDone(false), SrcDone(false),
+		  ContentsMTime(0) {};
 };
 									/*}}}*/
 
@@ -130,8 +135,6 @@ void PackageMap::GetGeneral(Configuration &Setup,Configuration &Block)
    PkgExt = Block.Find("Packages::Extensions",
 		       Setup.Find("Default::Packages::Extensions",".deb").c_str());
    
-   Permissions = Setup.FindI("Default::FileMode",0644);
-   
    if (FLFile.empty() == false)
       FLFile = flCombine(Setup.Find("Dir::FileListDir"),FLFile);
    
@@ -170,6 +173,9 @@ bool PackageMap::GenPackages(Configuration &Setup,struct CacheDB::Stats &Stats)
    Packages.DirStrip = ArchiveDir;
    Packages.InternalPrefix = flCombine(ArchiveDir,InternalPrefix);
 
+   Packages.TransWriter = TransWriter;
+   Packages.LongDescription = LongDesc;
+
    Packages.Stats.DeLinkBytes = Stats.DeLinkBytes;
    Packages.DeLinkLimit = DeLinkLimit;
 
@@ -437,6 +443,8 @@ void LoadTree(vector<PackageMap> &PkgList,Configuration &Setup)
 			    "$(DIST)/$(SECTION)/source/");
    string DPkg = Setup.Find("TreeDefault::Packages",
 			    "$(DIST)/$(SECTION)/binary-$(ARCH)/Packages");
+   string DTrans = Setup.Find("TreeDefault::Translation",
+			    "$(DIST)/$(SECTION)/i18n/Translation-en");
    string DIPrfx = Setup.Find("TreeDefault::InternalPrefix",
 			    "$(DIST)/$(SECTION)/");
    string DContents = Setup.Find("TreeDefault::Contents",
@@ -449,6 +457,12 @@ void LoadTree(vector<PackageMap> &PkgList,Configuration &Setup)
    string DFLFile = Setup.Find("TreeDefault::FileList", "");
    string DSFLFile = Setup.Find("TreeDefault::SourceFileList", "");
 
+   int const Permissions = Setup.FindI("Default::FileMode",0644);
+
+   bool const LongDescription = Setup.FindB("Default::LongDescription",
+					_config->FindB("APT::FTPArchive::LongDescription", true));
+   string const TranslationCompress = Setup.Find("Default::Translation::Compress",". gzip").c_str();
+
    // Process 'tree' type sections
    const Configuration::Item *Top = Setup.Tree("tree");
    for (Top = (Top == 0?0:Top->Child); Top != 0;)
@@ -462,17 +476,30 @@ void LoadTree(vector<PackageMap> &PkgList,Configuration &Setup)
       string Section;
       while (ParseQuoteWord(Sections,Section) == true)
       {
-	 string Tmp2 = Block.Find("Architectures");
 	 string Arch;
+	 struct SubstVar const Vars[] = {{"$(DIST)",&Dist},
+					 {"$(SECTION)",&Section},
+					 {"$(ARCH)",&Arch},
+					 {}};
+	 mode_t const Perms = Block.FindI("FileMode", Permissions);
+	 bool const LongDesc = Block.FindB("LongDescription", LongDescription);
+	 TranslationWriter *TransWriter;
+	 if (DTrans.empty() == false && LongDesc == false)
+	 {
+	    string const TranslationFile = flCombine(Setup.FindDir("Dir::ArchiveDir"),
+			SubstVar(Block.Find("Translation", DTrans.c_str()), Vars));
+	    string const TransCompress = Block.Find("Translation::Compress", TranslationCompress);
+	    TransWriter = new TranslationWriter(TranslationFile, TransCompress, Perms);
+	 }
+	 else
+	    TransWriter = NULL;
+
+	 string const Tmp2 = Block.Find("Architectures");
 	 const char *Archs = Tmp2.c_str();
 	 while (ParseQuoteWord(Archs,Arch) == true)
 	 {
-	    struct SubstVar Vars[] = {{"$(DIST)",&Dist},
-	                              {"$(SECTION)",&Section},
-	                              {"$(ARCH)",&Arch},
-	                              {}};
 	    PackageMap Itm;
-	    
+	    Itm.Permissions = Perms;
 	    Itm.BinOverride = SubstVar(Block.Find("BinOverride"),Vars);
 	    Itm.InternalPrefix = SubstVar(Block.Find("InternalPrefix",DIPrfx.c_str()),Vars);
 
@@ -492,6 +519,12 @@ void LoadTree(vector<PackageMap> &PkgList,Configuration &Setup)
 	       Itm.PkgFile = SubstVar(Block.Find("Packages",DPkg.c_str()),Vars);
 	       Itm.Tag = SubstVar("$(DIST)/$(SECTION)/$(ARCH)",Vars);
 	       Itm.Arch = Arch;
+	       Itm.LongDesc = LongDesc;
+	       if (TransWriter != NULL)
+	       {
+		  TransWriter->IncreaseRefCounter();
+		  Itm.TransWriter = TransWriter;
+	       }
 	       Itm.Contents = SubstVar(Block.Find("Contents",DContents.c_str()),Vars);
 	       Itm.ContentsHead = SubstVar(Block.Find("Contents::Header",DContentsH.c_str()),Vars);
 	       Itm.FLFile = SubstVar(Block.Find("FileList",DFLFile.c_str()),Vars);
@@ -501,6 +534,9 @@ void LoadTree(vector<PackageMap> &PkgList,Configuration &Setup)
  	    Itm.GetGeneral(Setup,Block);
 	    PkgList.push_back(Itm);
 	 }
+	 // we didn't use this TransWriter, so we can release it
+	 if (TransWriter != NULL && TransWriter->GetRefCounter() == 0)
+	    delete TransWriter;
       }
       
       Top = Top->Next;
@@ -789,7 +825,12 @@ bool Generate(CommandLine &CmdL)
       
       delete [] List;
    }
-   
+
+   // close the Translation master files
+   for (vector<PackageMap>::iterator I = PkgList.begin(); I != PkgList.end(); I++)
+      if (I->TransWriter != NULL && I->TransWriter->DecreaseRefCounter() == 0)
+	 delete I->TransWriter;
+
    if (_config->FindB("APT::FTPArchive::Contents",true) == false)
       return true;
    

+ 53 - 2
ftparchive/writer.cc

@@ -300,7 +300,7 @@ bool FTWScanner::Delink(string &FileName,const char *OriginalPath,
 /* */
 PackagesWriter::PackagesWriter(string const &DB,string const &Overrides,string const &ExtOverrides,
 			       string const &Arch) :
-   FTWScanner(Arch), Db(DB), Stats(Db.Stats)
+   FTWScanner(Arch), Db(DB), Stats(Db.Stats), TransWriter(NULL)
 {
    Output = stdout;
    SetExts(".deb .udeb");
@@ -317,7 +317,7 @@ PackagesWriter::PackagesWriter(string const &DB,string const &Overrides,string c
 
    if (Db.Loaded() == false)
       DoContents = false;
-      
+
    // Read the override file
    if (Overrides.empty() == false && Over.ReadOverride(Overrides) == false)
       return;
@@ -448,6 +448,8 @@ bool PackagesWriter::DoPackage(string FileName)
       descmd5.Add(desc.c_str());
       DescriptionMd5 = descmd5.Result().Value();
       SetTFRewriteData(Changes[End++], "Description-md5", DescriptionMd5.c_str());
+      if (TransWriter != NULL)
+	 TransWriter->DoPackage(Package, desc, DescriptionMd5);
    }
 
    // Rewrite the maintainer field if necessary
@@ -494,6 +496,55 @@ bool PackagesWriter::DoPackage(string FileName)
 }
 									/*}}}*/
 
+// TranslationWriter::TranslationWriter - Constructor			/*{{{*/
+// ---------------------------------------------------------------------
+/* Create a Translation-Master file for this Packages file */
+TranslationWriter::TranslationWriter(string const &File, string const &TransCompress,
+					mode_t const &Permissions) : Output(NULL),
+							RefCounter(0)
+{
+   if (File.empty() == true)
+      return;
+
+   Comp = new MultiCompress(File, TransCompress, Permissions);
+   Output = Comp->Input;
+}
+									/*}}}*/
+// TranslationWriter::DoPackage - Process a single package		/*{{{*/
+// ---------------------------------------------------------------------
+/* Create a Translation-Master file for this Packages file */
+bool TranslationWriter::DoPackage(string const &Pkg, string const &Desc,
+				  string const &MD5)
+{
+   if (Output == NULL)
+      return true;
+
+   // Different archs can include different versions and therefore
+   // different descriptions - so we need to check for both name and md5.
+   string const Record = Pkg + ":" + MD5;
+
+   if (Included.find(Record) != Included.end())
+      return true;
+
+   fprintf(Output, "Package: %s\nDescription-md5: %s\nDescription-en: %s\n",
+	   Pkg.c_str(), MD5.c_str(), Desc.c_str());
+
+   Included.insert(Record);
+   return true;
+}
+									/*}}}*/
+// TranslationWriter::~TranslationWriter - Destructor			/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+TranslationWriter::~TranslationWriter()
+{
+   if (Comp == NULL)
+      return;
+
+   delete Comp;
+}
+									/*}}}*/
+
 // SourcesWriter::SourcesWriter - Constructor				/*{{{*/
 // ---------------------------------------------------------------------
 /* */

+ 21 - 0
ftparchive/writer.h

@@ -19,8 +19,10 @@
 #include <iostream>
 #include <vector>
 #include <map>
+#include <set>
 
 #include "cachedb.h"
+#include "multicompress.h"
 #include "override.h"
 #include "apt-ftparchive.h"
 
@@ -72,6 +74,24 @@ class FTWScanner
    FTWScanner(string const &Arch = string());
 };
 
+class TranslationWriter
+{
+   MultiCompress *Comp;
+   FILE *Output;
+   std::set<string> Included;
+   unsigned short RefCounter;
+
+   public:
+   void IncreaseRefCounter() { ++RefCounter; };
+   unsigned short DecreaseRefCounter() { return (RefCounter == 0) ? 0 : --RefCounter; };
+   unsigned short GetRefCounter() const { return RefCounter; };
+   bool DoPackage(string const &Pkg, string const &Desc, string const &MD5);
+
+   TranslationWriter(string const &File, string const &TransCompress, mode_t const &Permissions);
+   TranslationWriter() : Comp(NULL), Output(NULL), RefCounter(0) {};
+   ~TranslationWriter();
+};
+
 class PackagesWriter : public FTWScanner
 {
    Override Over;
@@ -93,6 +113,7 @@ class PackagesWriter : public FTWScanner
    string DirStrip;
    FILE *Output;
    struct CacheDB::Stats &Stats;
+   TranslationWriter *TransWriter;
 
    inline bool ReadOverride(string const &File) {return Over.ReadOverride(File);};
    inline bool ReadExtraOverride(string const &File) 

Datei-Diff unterdrückt, da er zu groß ist
+ 201 - 166
po/apt-all.pot


+ 39 - 0
test/libapt/commandlineasstring_test.cc

@@ -0,0 +1,39 @@
+#include <apt-pkg/cmndline.h>
+#include <apt-pkg/configuration.h>
+
+#include <string>
+
+#include "assert.h"
+
+class CLT: public CommandLine {
+
+	public:
+	std::string static AsString(const char * const * const argv,
+				    unsigned int const argc) {
+		std::string const static conf = "Commandline::AsString";
+		_config->Clear(conf);
+		SaveInConfig(argc, argv);
+		return _config->Find(conf);
+	}
+};
+
+#define CMD(y,z) equals(CLT::AsString(argv, y), z);
+
+int main() {
+	{
+		const char* const argv[] = {"apt-get", "install", "-sf"};
+		CMD(3, "apt-get install -sf");
+	}
+	{
+		const char* const argv[] = {"apt-cache", "-s", "apt", "-so", "Debug::test=Test"};
+		CMD(5, "apt-cache -s apt -so Debug::test=Test");
+	}
+	{
+		const char* const argv[] = {"apt-cache", "-s", "apt", "-so", "Debug::test=Das ist ein Test"};
+		CMD(5, "apt-cache -s apt -so Debug::test=\"Das ist ein Test\"");
+	}
+	{
+		const char* const argv[] = {"apt-cache", "-s", "apt", "--hallo", "test=1.0"};
+		CMD(5, "apt-cache -s apt --hallo test=1.0");
+	}
+}

+ 123 - 0
test/libapt/compareversion_test.cc

@@ -0,0 +1,123 @@
+// -*- mode: cpp; mode: fold -*-
+// Description								/*{{{*/
+/* ######################################################################
+
+   Version Test - Simple program to run through a file and comare versions.
+   
+   Each version is compared and the result is checked against an expected
+   result in the file. The format of the file is
+       a b Res
+   Where Res is -1, 1, 0. dpkg -D=1 --compare-versions a "<" b can be
+   used to determine what Res should be. # at the start of the line
+   is a comment and blank lines are skipped
+
+   The runner will also call dpkg --compare-versions to check if APT and
+   dpkg have (still) the same idea.
+   
+   ##################################################################### */
+									/*}}}*/
+#include <apt-pkg/macros.h>
+#include <apt-pkg/error.h>
+#include <apt-pkg/version.h>
+#include <apt-pkg/debversion.h>
+#include <apt-pkg/fileutl.h>
+#include <iostream>
+#include <fstream>
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+using namespace std;
+
+bool callDPkg(const char *val, const char *ref, const char &op) {
+   pid_t Process = ExecFork();
+   if (Process == 0)
+   {
+      const char * args[6];
+      args[0] = "/usr/bin/dpkg";
+      args[1] = "--compare-versions";
+      args[2] = val;
+      args[3] = (op == 1) ? ">>" : ( (op == 0) ? "=" : "<<");
+      args[4] = ref;
+      args[5] = 0;
+      execv(args[0], (char**) args);
+      exit(1);
+   }
+   int Ret;
+   waitpid(Process, &Ret, 0);
+   return WIFEXITED(Ret) == true && WEXITSTATUS(Ret) == 0;
+}
+
+void assertVersion(int const &CurLine, string const &A, string const &B, int const &Expected) {
+   int Res = debVS.CmpVersion(A.c_str(), B.c_str());
+   bool const dpkg = callDPkg(A.c_str(),B.c_str(), Expected);
+   Res = (Res < 0) ? -1 : ( (Res > 0) ? 1 : Res);
+
+   if (Res != Expected)
+      _error->Error("Comparison failed on line %u. '%s' '%s' '%s' %i != %i",CurLine,A.c_str(),((Expected == 1) ? "<<" : ( (Expected == 0) ? "=" : ">>")) ,B.c_str(),Res,Expected);
+   if (dpkg == false)
+      _error->Error("DPkg differ with line: %u. '%s' '%s' '%s' == false",CurLine,A.c_str(),((Expected == 1) ? "<<" : ( (Expected == 0) ? "=" : ">>")),B.c_str());
+}
+
+bool RunTest(const char *File)
+{
+   ifstream F(File,ios::in);
+   if (!F != 0)
+      return false;
+
+   char Buffer[300];
+   int CurLine = 0;
+   
+   while (1)
+   {
+      F.getline(Buffer,sizeof(Buffer));
+      CurLine++;
+      if (F.eof() != 0)
+	 return true;
+      if (!F != 0)
+	 return _error->Error("Line %u in %s is too long",CurLine,File);
+
+      // Comment
+      if (Buffer[0] == '#' || Buffer[0] == 0)
+	 continue;
+      
+      // First version
+      char *I;
+      char *Start = Buffer;
+      for (I = Buffer; *I != 0 && *I != ' '; I++);
+      string A(Start, I - Start);
+
+      if (*I == 0)
+	 return _error->Error("Invalid line %u",CurLine);
+      
+      // Second version
+      I++;
+      Start = I;
+      for (I = Start; *I != 0 && *I != ' '; I++);
+      string B(Start,I - Start);
+      
+      if (*I == 0 || I[1] == 0)
+	 return _error->Error("Invalid line %u",CurLine);
+      
+      // Result
+      I++;
+      int const Expected = atoi(I);
+      assertVersion(CurLine, A, B, Expected);
+      // Check the reverse as well
+      assertVersion(CurLine, B, A, Expected*-1);
+   }
+}
+
+int main(int argc, char *argv[])
+{
+   if (argc <= 1)
+      RunTest("../versions.lst");
+   else
+      RunTest(argv[1]);
+
+   // Print any errors or warnings found
+   _error->DumpErrors();
+   return 0;
+}

+ 12 - 0
test/libapt/makefile

@@ -23,3 +23,15 @@ PROGRAM = GetListOfFilesInDir${BASENAME}
 SLIBS = -lapt-pkg
 SOURCE = getlistoffilesindir_test.cc
 include $(PROGRAM_H)
+
+# Program for testing CommandLine reconstruction
+PROGRAM = commandlineasstring${BASENAME}
+SLIBS = -lapt-pkg
+SOURCE = commandlineasstring_test.cc
+include $(PROGRAM_H)
+
+# Program for testing debians version comparing
+PROGRAM = compareversion${BASENAME}
+SLIBS = -lapt-pkg
+SOURCE = compareversion_test.cc
+include $(PROGRAM_H)

+ 0 - 7
test/makefile

@@ -24,13 +24,6 @@ LIB_MAKES = apt-pkg/makefile apt-inst/makefile
 SOURCE = scratch.cc
 include $(PROGRAM_H)
 
-# Version compare tester
-PROGRAM=versiontest
-SLIBS = -lapt-pkg 
-LIB_MAKES = apt-pkg/makefile
-SOURCE = versiontest.cc
-include $(PROGRAM_H)
-
 # Version compare tester
 PROGRAM=testextract
 SLIBS = -lapt-pkg -lapt-inst

+ 60 - 4
test/versions.lst

@@ -10,10 +10,11 @@
 1.3 1.2.2 1
 
 # Important attributes
-- . -1
-p - -1
-a - -1
-z - -1
+# disabled as dpkg --compare-versions doesn't like them…
+#- . -1
+#p - -1
+#a - -1
+#z - -1
 a . -1
 z . -1
 
@@ -22,6 +23,10 @@ z . -1
 1:1.25-4 1:1.25-8 -1
 0:1.18.36 1.18.36 0
 
+# native version
+1.18.36 1.18.35 1
+0:1.18.36 1.18.35 1
+
 # Funky, but allowed, characters in upstream version
 9:1.18.36:5.4-20 10:0.5.1-22 -1
 9:1.18.36:5.4-20 9:1.18.36:5.5-1 -1
@@ -49,3 +54,54 @@ III-alpha9.8 III-alpha9.8-1.5 -1
 
 # #205960
 3.0~rc1-1 3.0-1 -1
+
+# #573592 - debian policy 5.6.12
+1.0 1.0-0 0
+0.2 1.0-0 -1
+1.0 1.0-0+b1 -1
+1.0 1.0-0~ 1
+
+# if a version includes a dash
+# it should be the debrev dash - policy says so…
+0:0-0-0 0-0 1
+
+# do we like strange versions? Yes we like strange versions…
+0 0 0
+0 00 0
+
+# "steal" the testcases from cupt
+1.2.3 1.2.3 0 # identical
+4.4.3-2 4.4.3-2 0 # identical
+1:2ab:5 1:2ab:5 0 # this is correct...
+7:1-a:b-5 7:1-a:b-5 0 # and this
+57:1.2.3abYZ+~-4-5 57:1.2.3abYZ+~-4-5 0 # and those too
+1.2.3 0:1.2.3 0 # zero epoch
+1.2.3 1.2.3-0 0 # zero revision
+009 9 0 # zeroes...
+009ab5 9ab5 0 # there as well
+1.2.3 1.2.3-1 -1 # added non-zero revision
+1.2.3 1.2.4 -1 # just bigger
+1.2.4 1.2.3 1 # order doesn't matter
+1.2.24 1.2.3 1 # bigger, eh?
+0.10.0 0.8.7 1 # bigger, eh?
+3.2 2.3 1 # major number rocks
+1.3.2a 1.3.2 1 # letters rock
+0.5.0~git 0.5.0~git2 -1 # numbers rock
+2a 21 -1 # but not in all places
+1.3.2a 1.3.2b -1 # but there is another letter
+1:1.2.3 1.2.4 1 # epoch rocks
+1:1.2.3 1:1.2.4 -1 # bigger anyway
+1.2a+~bCd3 1.2a++ -1 # tilde doesn't rock
+1.2a+~bCd3 1.2a+~ 1 # but first is longer!
+5:2 304-2 1 # epoch rocks
+5:2 304:2 -1 # so big epoch?
+25:2 3:2 1 # 25 > 3, obviously
+1:2:123 1:12:3 -1 # 12 > 2
+1.2-5 1.2-3-5 -1 # 1.2 < 1.2-3
+5.10.0 5.005 1 # preceding zeroes don't matters
+3a9.8 3.10.2 -1 # letters are before all letter symbols
+3a9.8 3~10 1 # but after the tilde
+1.4+OOo3.0.0~ 1.4+OOo3.0.0-4 -1 # another tilde check
+2.4.7-1 2.4.7-z -1 # revision comparing
+1.002-1+b2 1.00 1 # whatever...
+2.2.4-47978_Debian_lenny 2.2.4-47978_Debian_lenny 0 # and underscore...

+ 0 - 233
test/versiontest.cc

@@ -1,233 +0,0 @@
-// -*- mode: cpp; mode: fold -*-
-// Description								/*{{{*/
-// $Id: versiontest.cc,v 1.5 2003/08/18 15:55:19 mdz Exp $
-/* ######################################################################
-
-   Version Test - Simple program to run through a file and comare versions.
-   
-   Each version is compared and the result is checked against an expected
-   result in the file. The format of the file is
-       a b Res
-   Where Res is -1, 1, 0. dpkg -D=1 --compare-versions a "<" b can be
-   used to determine what Res should be. # at the start of the line
-   is a comment and blank lines are skipped
-   
-   ##################################################################### */
-									/*}}}*/
-#include <apt-pkg/macros.h>
-#include <apt-pkg/error.h>
-#include <apt-pkg/version.h>
-#include <apt-pkg/debversion.h>
-#include <iostream>
-#include <fstream>
-
-using namespace std;
-
-  static int verrevcmp(const char *val, const char *ref) 
-{
-   int vc, rc;
-   long vl, rl;
-   const char *vp, *rp;
-   
-   if (!val) 
-      val = "";
-   if (!ref) 
-      ref = "";
-   for (;;) 
-   {
-      vp = val;  
-      while (*vp && !isdigit(*vp)) 
-	 vp++;
-      rp = ref;  
-      while (*rp && !isdigit(*rp)) 
-	 rp++;
-      for (;;) 
-      {
-	 vc= val == vp ? 0 : *val++;
-	 rc= ref == rp ? 0 : *ref++;
-	 if (!rc && !vc)
-	    break;
-	 if (vc && !isalpha(vc)) 
-	    vc += 256; /* assumes ASCII character set */
-	 if (rc && !isalpha(rc)) 
-	    rc += 256;
-	 if (vc != rc) 
-	    return vc - rc;
-      }
-      val = vp;
-      ref = rp;
-      vl = 0;
-      if (isdigit(*vp)) 
-	 vl = strtol(val,(char**)&val,10);
-      rl = 0;
-      if (isdigit(*rp)) 
-	 rl = strtol(ref,(char**)&ref,10);
-      if (vl != rl) 
-	 return vl - rl;
-      if (!*val && !*ref) 
-	 return 0;
-      if (!*val) 
-	 return -1;
-      if (!*ref) 
-	 return +1;
-   }
-}
-
-#if 0
-static int verrevcmp(const char *val, const char *ref) 
-{   
-   int vc, rc;
-   long vl, rl;
-   const char *vp, *rp;
-   
-   if (!val) val= "";
-   if (!ref) ref= "";
-   for (;;) 
-   {
-      vp= val;  while (*vp && !isdigit(*vp) && *vp != '~') vp++;
-      rp= ref;  while (*rp && !isdigit(*rp) && *rp != '~') rp++;
-      for (;;)
-      {	 
-	 vc= val == vp ? 0 : *val++;
-	 rc= ref == rp ? 0 : *ref++;
-	 if (!rc && !vc) break;
-	 if (vc && !isalpha(vc)) vc += 256; /* assumes ASCII character set */
-	 if (rc && !isalpha(rc)) rc += 256;
-	 if (vc != rc) return vc - rc;
-      }
-      
-      val= vp;
-      ref= rp;
-      if (*vp == '~') val++;
-      if (*rp == '~') ref++;
-      vl=0;  if (isdigit(*val)) vl= strtol(val,(char**)&val,10);
-      rl=0;  if (isdigit(*ref)) rl= strtol(ref,(char**)&ref,10);
-      if (vl == 0 && rl == 0)
-      {
-	 if (*vp == '~' && *rp != '~') return -1;
-	 if (*vp != '~' && *rp == '~') return +1;
-      }
-      if (*vp == '~')
-	 vl *= -1;
-      if (*rp == '~')
-	 rl *= -1;
-      if (vl != rl) return vl - rl;
-      if (!*val && !*ref) return 0;
-      if (!*val)
-      {
-	 if (*ref == '~')
-	    return +1;
-         else
-	    return -1;
-      }
-      
-      if (!*ref)
-      {
-	 if (*val == '~')
-	    return -1;
-	 else
-	    return +1;
-      }      
-   }   
-}
-#endif
-    
-bool RunTest(const char *File)
-{
-   ifstream F(File,ios::in);
-   if (!F != 0)
-      return false;
-
-   char Buffer[300];
-   int CurLine = 0;
-   
-   while (1)
-   {
-      F.getline(Buffer,sizeof(Buffer));
-      CurLine++;
-      if (F.eof() != 0)
-	 return true;
-      if (!F != 0)
-	 return _error->Error("Line %u in %s is too long",CurLine,File);
-
-      // Comment
-      if (Buffer[0] == '#' || Buffer[0] == 0)
-	 continue;
-      
-      // First version
-      char *I;
-      char *Start = Buffer;
-      for (I = Buffer; *I != 0 && *I != ' '; I++);
-      string A(Start, I - Start);
-
-      if (*I == 0)
-	 return _error->Error("Invalid line %u",CurLine);
-      
-      // Second version
-      I++;
-      Start = I;
-      for (I = Start; *I != 0 && *I != ' '; I++);
-      string B(Start,I - Start);
-      
-      if (*I == 0 || I[1] == 0)
-	 return _error->Error("Invalid line %u",CurLine);
-      
-      // Result
-      I++;
-      int Expected = atoi(I);
-      int Res = debVS.CmpVersion(A.c_str(), B.c_str());
-      int Res2 = verrevcmp(A.c_str(),B.c_str());
-      cout << "'" << A << "' ? '" << B << "' = " << Res << " (= " << Expected << ") " << Res2 << endl;
-
-      if (Res < 0)
-           Res = -1;
-      else if (Res > 0)
-           Res = 1;
-
-      if (Res != Expected)
-	 _error->Error("Comparison failed on line %u. '%s' ? '%s' %i != %i",CurLine,A.c_str(),B.c_str(),Res,Expected);
-
-      // Check the reverse as well
-      Expected = -1*Expected;
-      Res = debVS.CmpVersion(B.c_str(), A.c_str());
-      Res2 = verrevcmp(B.c_str(),A.c_str());
-
-      cout << "'" << B << "' ? '" << A << "' = " << Res << " (= " << Expected << ") " << Res2 << endl;
-
-      if (Res < 0)
-           Res = -1;
-      else if (Res > 0)
-           Res = 1;
-
-      if (Res != Expected)
-	 _error->Error("Comparison failed on line %u. '%s' ? '%s' %i != %i",CurLine,B.c_str(),A.c_str(),Res,Expected);
-   }
-}
-
-int main(int argc, char *argv[])
-{
-   if (argc <= 1)
-   {
-      cerr << "You must specify a test file" << endl;
-      return 0;
-   }
-   
-   RunTest(argv[1]);
-
-   // Print any errors or warnings found
-   if (_error->empty() == false)
-   {
-      string Err;
-      while (_error->empty() == false)
-      {
-	 
-	 bool Type = _error->PopMessage(Err);
-	 if (Type == true)
-	    cout << "E: " << Err << endl;
-	 else
-	    cout << "W: " << Err << endl;
-      }
-      
-      return 0;
-   }
-}