瀏覽代碼

merge MultiArch-ABI. We don't support MultiArch yet (as most other tools),
but we support the usage of the new ABI so libapt users
can start to prepare for MultiArch (Closes: #536029)

David Kalnischkies 16 年之前
父節點
當前提交
c67dc114ea

+ 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*/)
 bool pkgSimulate::Install(PkgIterator iPkg,string /*File*/)
 {
 {
    // Adapt the iterator
    // Adapt the iterator
-   PkgIterator Pkg = Sim.FindPkg(iPkg.Name());
+   PkgIterator Pkg = Sim.FindPkg(iPkg.Name(), iPkg.Arch());
    Flags[Pkg->ID] = 1;
    Flags[Pkg->ID] = 1;
    
    
    cout << "Inst ";
    cout << "Inst ";
    Describe(Pkg,cout,true,true);
    Describe(Pkg,cout,true,true);
    Sim.MarkInstall(Pkg,false);
    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.
    // Look for broken conflicts+predepends.
    for (PkgIterator I = Sim.PkgBegin(); I.end() == false; I++)
    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)
 bool pkgSimulate::Configure(PkgIterator iPkg)
 {
 {
    // Adapt the iterator
    // Adapt the iterator
-   PkgIterator Pkg = Sim.FindPkg(iPkg.Name());
+   PkgIterator Pkg = Sim.FindPkg(iPkg.Name(), iPkg.Arch());
    
    
    Flags[Pkg->ID] = 2;
    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);
 //   Sim.MarkInstall(Pkg,false);
    if (Sim[Pkg].InstBroken() == true)
    if (Sim[Pkg].InstBroken() == true)
    {
    {
@@ -181,10 +209,26 @@ bool pkgSimulate::Configure(PkgIterator iPkg)
 bool pkgSimulate::Remove(PkgIterator iPkg,bool Purge)
 bool pkgSimulate::Remove(PkgIterator iPkg,bool Purge)
 {
 {
    // Adapt the iterator
    // Adapt the iterator
-   PkgIterator Pkg = Sim.FindPkg(iPkg.Name());
+   PkgIterator Pkg = Sim.FindPkg(iPkg.Name(), iPkg.Arch());
 
 
    Flags[Pkg->ID] = 3;
    Flags[Pkg->ID] = 3;
    Sim.MarkDelete(Pkg);
    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)
    if (Purge == true)
       cout << "Purg ";
       cout << "Purg ";
    else
    else
@@ -491,11 +535,11 @@ void pkgProblemResolver::MakeScores()
    // Important Required Standard Optional Extra
    // Important Required Standard Optional Extra
    signed short PrioMap[] = {
    signed short PrioMap[] = {
       0,
       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 PrioEssentials = _config->FindI("pkgProblemResolver::Scores::Essentials",100);
    signed short PrioInstalledAndNotObsolete = _config->FindI("pkgProblemResolver::Scores::NotObsolete",1);
    signed short PrioInstalledAndNotObsolete = _config->FindI("pkgProblemResolver::Scores::NotObsolete",1);

+ 24 - 0
apt-pkg/aptconfiguration.cc

@@ -319,4 +319,28 @@ std::vector<std::string> const Configuration::getLanguages(bool const &All,
 		return codes;
 		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,
 	std::vector<std::string> static const getLanguages(bool const &All = false,
 			bool const &Cached = true, char const ** const Locale = 0);
 			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);
+
 									/*}}}*/
 									/*}}}*/
 };
 };
 									/*}}}*/
 									/*}}}*/

+ 344 - 378
apt-pkg/cacheiterators.h

@@ -1,6 +1,5 @@
 // -*- mode: cpp; mode: fold -*-
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
 // 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
    Cache Iterators - Iterators for navigating the cache structure
@@ -30,417 +29,384 @@
 									/*}}}*/
 									/*}}}*/
 #ifndef PKGLIB_CACHEITERATORS_H
 #ifndef PKGLIB_CACHEITERATORS_H
 #define 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 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							/*{{{*/
 // 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							/*{{{*/
 // 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							/*{{{*/
 // 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							/*{{{*/
 // 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							/*{{{*/
 // 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								/*{{{*/
 // 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								/*{{{*/
 // 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							/*{{{*/
 // 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 /*{{{*/
 // 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
 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
 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
 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
 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
 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
 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
 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
 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
 inline pkgCache::DescFileIterator pkgCache::DescIterator::FileList() const
-       {return DescFileIterator(*Owner,Owner->DescFileP + Desc->FileList);};
+       {return DescFileIterator(*Owner,Owner->DescFileP + S->FileList);};
 									/*}}}*/
 									/*}}}*/
 #endif
 #endif

+ 13 - 21
apt-pkg/cdrom.cc

@@ -6,6 +6,8 @@
 #include<apt-pkg/cdromutl.h>
 #include<apt-pkg/cdromutl.h>
 #include<apt-pkg/strutl.h>
 #include<apt-pkg/strutl.h>
 #include<apt-pkg/cdrom.h>
 #include<apt-pkg/cdrom.h>
+#include<apt-pkg/aptconfiguration.h>
+
 #include<sstream>
 #include<sstream>
 #include<fstream>
 #include<fstream>
 #include<config.h>
 #include<config.h>
@@ -216,33 +218,23 @@ int pkgCdrom::Score(string Path)
 /* Here we drop everything that is not this machines arch */
 /* Here we drop everything that is not this machines arch */
 bool pkgCdrom::DropBinaryArch(vector<string> &List)
 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++)
    for (unsigned int I = 0; I < List.size(); I++)
    {
    {
       const char *Str = List[I].c_str();
       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;
 	 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);
       List.erase(List.begin() + I);
-      I--;
+      --I; // the next entry is at the same index after the erase
    }
    }
    
    
    return true;
    return true;

+ 3 - 3
apt-pkg/clean.cc

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

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

@@ -56,33 +56,33 @@
 
 
 // some nice optional GNUC features
 // some nice optional GNUC features
 #if __GNUC__ >= 3
 #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))
+	/* 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
 #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 likely(x)	(x)
+	#define unlikely(x)	(x)
 #endif
 #endif
 
 
 // cold functions are unlikely() to be called
 // cold functions are unlikely() to be called
 #if (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) || __GNUC__ > 4
 #if (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) || __GNUC__ > 4
-        #define __cold  __attribute__ ((__cold__))
+	#define __cold	__attribute__ ((__cold__))
 #else
 #else
-        #define __cold  /* no cold marker */
+	#define __cold	/* no cold marker */
 #endif
 #endif
 
 
 #ifdef __GNUG__
 #ifdef __GNUG__
 // Methods have a hidden this parameter that is visible to this attribute
 // 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_1	__attribute__ ((format (printf, 2, 3)))
+	#define __like_printf_2	__attribute__ ((format (printf, 3, 4)))
 #else
 #else
-	#define __like_printf_1
-	#define __like_printf_2
+	#define __like_printf_1	/* no like-printf */
+	#define __like_printf_2	/* no like-printf */
 #endif
 #endif
 
 
 #endif
 #endif

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

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

+ 165 - 45
apt-pkg/deb/deblistparser.cc

@@ -31,10 +31,13 @@ static debListParser::WordList PrioList[] = {{"important",pkgCache::State::Impor
 
 
 // ListParser::debListParser - Constructor				/*{{{*/
 // 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	/*{{{*/
 // ListParser::UniqFindTagWrite - Find the tag and write a unq string	/*{{{*/
@@ -52,12 +55,38 @@ unsigned long debListParser::UniqFindTagWrite(const char *Tag)
 // ListParser::Package - Return the package name			/*{{{*/
 // ListParser::Package - Return the package name			/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* This is to return the name of the package this section describes */
 /* This is to return the name of the package this section describes */
-string debListParser::Package()
-{
-   string Result = Section.FindS("Package");
-   if (Result.empty() == true)
-      _error->Error("Encountered a section with no Package: header");
-   return Result;
+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			/*{{{*/
 // ListParser::Version - Return the version string			/*{{{*/
@@ -77,8 +106,31 @@ bool debListParser::NewVersion(pkgCache::VerIterator Ver)
 {
 {
    // Parse the section
    // Parse the section
    Ver->Section = UniqFindTagWrite("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
    // Archive Size
    Ver->Size = (unsigned)Section.FindI("Size");
    Ver->Size = (unsigned)Section.FindI("Size");
    
    
@@ -95,6 +147,25 @@ bool debListParser::NewVersion(pkgCache::VerIterator Ver)
 	 Ver->Priority = pkgCache::State::Extra;
 	 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)
    if (ParseDepends(Ver,"Depends",pkgCache::Dep::Depends) == false)
       return false;
       return false;
    if (ParseDepends(Ver,"Pre-Depends",pkgCache::Dep::PreDepends) == false)
    if (ParseDepends(Ver,"Pre-Depends",pkgCache::Dep::PreDepends) == false)
@@ -183,8 +254,12 @@ bool debListParser::UsePackage(pkgCache::PkgIterator Pkg,
 {
 {
    if (Pkg->Section == 0)
    if (Pkg->Section == 0)
       Pkg->Section = UniqFindTagWrite("Section");
       Pkg->Section = UniqFindTagWrite("Section");
-   if (Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false)
-      return false;
+
+   // Packages which are not from "our" arch doesn't get the essential flag
+   string const static myArch = _config->Find("APT::Architecture");
+   if (Pkg->Arch != 0 && myArch == Pkg.Arch())
+      if (Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false)
+	 return false;
    if (Section.FindFlag("Important",Pkg->Flags,pkgCache::Flag::Important) == false)
    if (Section.FindFlag("Important",Pkg->Flags,pkgCache::Flag::Important) == false)
       return false;
       return false;
 
 
@@ -534,8 +609,12 @@ bool debListParser::ParseDepends(pkgCache::VerIterator Ver,
    const char *Stop;
    const char *Stop;
    if (Section.Find(Tag,Start,Stop) == false)
    if (Section.Find(Tag,Start,Stop) == false)
       return true;
       return true;
-   
+
+   static std::vector<std::string> const archs = APT::Configuration::getArchitectures();
+   static bool const multiArch = archs.size() <= 1;
+
    string Package;
    string Package;
+   string const pkgArch = Ver.Arch(true);
    string Version;
    string Version;
    unsigned int Op;
    unsigned int Op;
 
 
@@ -544,8 +623,18 @@ bool debListParser::ParseDepends(pkgCache::VerIterator Ver,
       Start = ParseDepends(Start,Stop,Package,Version,Op);
       Start = ParseDepends(Start,Stop,Package,Version,Op);
       if (Start == 0)
       if (Start == 0)
 	 return _error->Error("Problem parsing dependency %s",Tag);
 	 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;
 	 return false;
       if (Start == Stop)
       if (Start == Stop)
 	 break;
 	 break;
@@ -560,29 +649,52 @@ bool debListParser::ParseProvides(pkgCache::VerIterator Ver)
 {
 {
    const char *Start;
    const char *Start;
    const char *Stop;
    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;
    return true;
 }
 }
 									/*}}}*/
 									/*}}}*/
@@ -613,16 +725,23 @@ bool debListParser::Step()
       /* See if this is the correct Architecture, if it isn't then we
       /* 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)
          drop the whole section. A missing arch tag only happens (in theory)
          inside the Status file, so that is a positive return */
          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;
 	 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();
       iOffset = Tags.Offset();
    }   
    }   
@@ -640,8 +759,9 @@ bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI,
    if (Tags.Step(Section) == false)
    if (Tags.Step(Section) == false)
       return 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
    // apt-secure does no longer download individual (per-section) Release
    // file. to provide Component pinning we use the section name now
    // 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
    // These all operate against the current section
    virtual string Package();
    virtual string Package();
+   virtual string Architecture();
+   virtual bool ArchitectureAll();
    virtual string Version();
    virtual string Version();
    virtual bool NewVersion(pkgCache::VerIterator Ver);
    virtual bool NewVersion(pkgCache::VerIterator Ver);
    virtual string Description();
    virtual string Description();
@@ -68,7 +70,7 @@ class debListParser : public pkgCacheGenerator::ListParser
 			    bool const &StripMultiArch = false);
 			    bool const &StripMultiArch = false);
    static const char *ConvertRelation(const char *I,unsigned int &Op);
    static const char *ConvertRelation(const char *I,unsigned int &Op);
 
 
-   debListParser(FileFd *File);
+   debListParser(FileFd *File, string const &Arch = "");
 };
 };
 
 
 #endif
 #endif

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

@@ -8,9 +8,11 @@
 #include <apt-pkg/aptconfiguration.h>
 #include <apt-pkg/aptconfiguration.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/error.h>
 
 
+#include <set>
+
 using namespace std;
 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) + ' ';
    string Info = ::URI::SiteOnly(URI) + ' ';
    if (Dist[Dist.size() - 1] == '/')
    if (Dist[Dist.size() - 1] == '/')
@@ -19,7 +21,11 @@ string debReleaseIndex::Info(const char *Type, const string Section) const
          Info += Dist;
          Info += Dist;
    }
    }
    else
    else
-      Info += Dist + '/' + Section;   
+   {
+      Info += Dist + '/' + Section;
+      if (Arch.empty() == true)
+	 Info += " " + Arch;
+   }
    Info += " ";
    Info += " ";
    Info += Type;
    Info += Type;
    return Info;
    return Info;
@@ -61,16 +67,21 @@ string debReleaseIndex::MetaIndexURI(const char *Type) const
    return Res;
    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 ="";
    string Res ="";
    if (Dist[Dist.size() - 1] != '/')
    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;
    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] == '/')
    if (Dist[Dist.size() - 1] == '/')
    {
    {
@@ -82,10 +93,10 @@ string debReleaseIndex::IndexURI(const char *Type, const string Section) const
       return Res + Type;
       return Res + Type;
    }
    }
    else
    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 ="";
    string Res ="";
    if (Dist[Dist.size() - 1] != '/')
    if (Dist[Dist.size() - 1] != '/')
@@ -93,7 +104,7 @@ string debReleaseIndex::SourceIndexURISuffix(const char *Type, const string Sect
    return Res + Type;
    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;
    string Res;
    if (Dist[Dist.size() - 1] == '/')
    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);
       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
    // special case for --print-uris
    if (GetAll) {
    if (GetAll) {
@@ -170,24 +198,28 @@ bool debReleaseIndex::GetIndexes(pkgAcquire *Owner, bool GetAll) const
 		     ComputeIndexTargets(),
 		     ComputeIndexTargets(),
 		     new indexRecords (Dist));
 		     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
 bool debReleaseIndex::IsTrusted() const
@@ -204,73 +236,113 @@ bool debReleaseIndex::IsTrusted() const
    return false;
    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
 class debSLTypeDebian : public pkgSourceList::Type
 {
 {
    protected:
    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()) ? ExplodeString(arch->second, ',') :
+				APT::Configuration::getArchitectures();
+
+      for (vector<metaIndex *>::const_iterator I = List.begin();
 	   I != List.end(); I++)
 	   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.
       // No currently created Release file indexes this entry, so we create a new one.
       // XXX determine whether this release is trusted or not
       // 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);
       List.push_back(Deb);
       return true;
       return true;
    }
    }
@@ -280,10 +352,11 @@ class debSLTypeDeb : public debSLTypeDebian
 {
 {
    public:
    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()
    debSLTypeDeb()
@@ -297,10 +370,11 @@ class debSLTypeDebSrc : public debSLTypeDebian
 {
 {
    public:
    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()
    debSLTypeDebSrc()

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

@@ -5,40 +5,44 @@
 #include <apt-pkg/metaindex.h>
 #include <apt-pkg/metaindex.h>
 #include <apt-pkg/sourcelist.h>
 #include <apt-pkg/sourcelist.h>
 
 
+#include <map>
+
 class debReleaseIndex : public metaIndex {
 class debReleaseIndex : public metaIndex {
    public:
    public:
 
 
    class debSectionEntry
    class debSectionEntry
    {
    {
       public:
       public:
-      debSectionEntry (string Section, bool IsSrc);
-      bool IsSrc;
-      string Section;
+      debSectionEntry (string const &Section, bool const &IsSrc);
+      string const Section;
+      bool const IsSrc;
    };
    };
 
 
    private:
    private:
-   vector <const debSectionEntry *> SectionEntries;
+   std::map<string, vector<debSectionEntry const*> > ArchEntries;
 
 
    public:
    public:
 
 
-   debReleaseIndex(string URI, string Dist);
+   debReleaseIndex(string const &URI, string const &Dist);
    ~debReleaseIndex();
    ~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;
    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 MetaIndexInfo(const char *Type) const;
    string MetaIndexFile(const char *Types) const;
    string MetaIndexFile(const char *Types) const;
    string MetaIndexURI(const char *Type) 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 vector <pkgIndexFile *> *GetIndexFiles();
 
 
    virtual bool IsTrusted() const;
    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);
    void PushSectionEntry(const debSectionEntry *Entry);
 };
 };
 
 

+ 308 - 64
apt-pkg/depcache.cc

@@ -17,6 +17,7 @@
 #include <apt-pkg/fileutl.h>
 #include <apt-pkg/fileutl.h>
 #include <apt-pkg/strutl.h>
 #include <apt-pkg/strutl.h>
 #include <apt-pkg/configuration.h>
 #include <apt-pkg/configuration.h>
+#include <apt-pkg/aptconfiguration.h>
 #include <apt-pkg/pkgsystem.h>
 #include <apt-pkg/pkgsystem.h>
 #include <apt-pkg/tagfile.h>
 #include <apt-pkg/tagfile.h>
 
 
@@ -164,34 +165,46 @@ bool pkgDepCache::Init(OpProgress *Prog)
 bool pkgDepCache::readStateFile(OpProgress *Prog)			/*{{{*/
 bool pkgDepCache::readStateFile(OpProgress *Prog)			/*{{{*/
 {
 {
    FileFd state_file;
    FileFd state_file;
-   string state = _config->FindDir("Dir::State") + "extended_states";
+   string const state = _config->FindDir("Dir::State") + "extended_states";
    if(FileExists(state)) {
    if(FileExists(state)) {
       state_file.Open(state, FileFd::ReadOnly);
       state_file.Open(state, FileFd::ReadOnly);
-      int file_size = state_file.Size();
+      int const file_size = state_file.Size();
       if(Prog != NULL)
       if(Prog != NULL)
 	 Prog->OverallProgress(0, file_size, 1, 
 	 Prog->OverallProgress(0, file_size, 1, 
 			       _("Reading state information"));
 			       _("Reading state information"));
 
 
       pkgTagFile tagfile(&state_file);
       pkgTagFile tagfile(&state_file);
       pkgTagSection section;
       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)) {
       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)
       if(Prog != NULL)
 	 Prog->OverallProgress(file_size, file_size, 1,
 	 Prog->OverallProgress(file_size, file_size, 1,
@@ -203,13 +216,13 @@ bool pkgDepCache::readStateFile(OpProgress *Prog)			/*{{{*/
 									/*}}}*/
 									/*}}}*/
 bool pkgDepCache::writeStateFile(OpProgress *prog, bool InstalledOnly)	/*{{{*/
 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)
    if(debug_autoremove)
       std::clog << "pkgDepCache::writeStateFile()" << std::endl;
       std::clog << "pkgDepCache::writeStateFile()" << std::endl;
 
 
    FileFd StateFile;
    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 it does not exist, create a empty one
    if(!FileExists(state)) 
    if(!FileExists(state)) 
@@ -224,7 +237,7 @@ bool pkgDepCache::writeStateFile(OpProgress *prog, bool InstalledOnly)	/*{{{*/
 			   state.c_str());
 			   state.c_str());
 
 
    FILE *OutFile;
    FILE *OutFile;
-   string outfile = state + ".tmp";
+   string const outfile = state + ".tmp";
    if((OutFile = fopen(outfile.c_str(),"w")) == NULL)
    if((OutFile = fopen(outfile.c_str(),"w")) == NULL)
       return _error->Error(_("Failed to write temporary StateFile %s"),
       return _error->Error(_("Failed to write temporary StateFile %s"),
 			   outfile.c_str());
 			   outfile.c_str());
@@ -236,9 +249,12 @@ bool pkgDepCache::writeStateFile(OpProgress *prog, bool InstalledOnly)	/*{{{*/
    const char *nullreorderlist[] = {0};
    const char *nullreorderlist[] = {0};
    while(tagfile.Step(section)) {
    while(tagfile.Step(section)) {
 	 string const 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
 	 // Silently ignore unknown packages and packages with no actual
 	 // version.
 	 // version.
-	 pkgCache::PkgIterator pkg=Cache->FindPkg(pkgname);
+	 pkgCache::PkgIterator pkg = Cache->FindPkg(pkgname, pkgarch);
 	 if(pkg.end() || pkg.VersionList().end()) 
 	 if(pkg.end() || pkg.VersionList().end()) 
 	    continue;
 	    continue;
 	 StateCache const &P = PkgState[pkg->ID];
 	 StateCache const &P = PkgState[pkg->ID];
@@ -251,22 +267,26 @@ bool pkgDepCache::writeStateFile(OpProgress *prog, bool InstalledOnly)	/*{{{*/
 	    // The section is obsolete if it contains no other tag
 	    // The section is obsolete if it contains no other tag
 	    unsigned int const count = section.Count();
 	    unsigned int const count = section.Count();
 	    if (count < 2 ||
 	    if (count < 2 ||
-		(count == 2 && section.Exists("Auto-Installed")))
+		(count == 2 && section.Exists("Auto-Installed")) ||
+		(count == 3 && section.Exists("Auto-Installed") && section.Exists("Architecture")))
 	       continue;
 	       continue;
 	    else
 	    else
 	       newAuto = false;
 	       newAuto = false;
 	 }
 	 }
 	 if(_config->FindB("Debug::pkgAutoRemove",false))
 	 if(_config->FindB("Debug::pkgAutoRemove",false))
 	    std::clog << "Update existing AutoInstall info: " 
 	    std::clog << "Update existing AutoInstall info: " 
-		      << pkgname << 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[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);
 	 TFRewrite(OutFile, section, nullreorderlist, rewrite);
 	 fprintf(OutFile,"\n");
 	 fprintf(OutFile,"\n");
-	 pkgs_seen.insert(pkgname);
+	 pkgs_seen.insert(pkg.FullName());
    }
    }
    
    
    // then write the ones we have not seen yet
    // then write the ones we have not seen yet
@@ -274,9 +294,9 @@ bool pkgDepCache::writeStateFile(OpProgress *prog, bool InstalledOnly)	/*{{{*/
    for(pkgCache::PkgIterator pkg=Cache->PkgBegin(); !pkg.end(); pkg++) {
    for(pkgCache::PkgIterator pkg=Cache->PkgBegin(); !pkg.end(); pkg++) {
       StateCache const &P = PkgState[pkg->ID];
       StateCache const &P = PkgState[pkg->ID];
       if(P.Flags & Flag::Auto) {
       if(P.Flags & Flag::Auto) {
-	 if (pkgs_seen.find(pkg.Name()) != pkgs_seen.end()) {
+	 if (pkgs_seen.find(pkg.FullName()) != pkgs_seen.end()) {
 	    if(debug_autoremove)
 	    if(debug_autoremove)
-	       std::clog << "Skipping already written " << pkg.Name() << std::endl;
+	       std::clog << "Skipping already written " << pkg.FullName() << std::endl;
 	    continue;
 	    continue;
 	 }
 	 }
 	 // skip not installed ones if requested
 	 // skip not installed ones if requested
@@ -284,14 +304,16 @@ bool pkgDepCache::writeStateFile(OpProgress *prog, bool InstalledOnly)	/*{{{*/
 	     (pkg->CurrentVer == 0 && P.Mode != ModeInstall) ||
 	     (pkg->CurrentVer == 0 && P.Mode != ModeInstall) ||
 	     (pkg->CurrentVer != 0 && P.Mode == ModeDelete)))
 	     (pkg->CurrentVer != 0 && P.Mode == ModeDelete)))
 	    continue;
 	    continue;
+	 const char* const pkgarch = pkg.Arch();
+	 if (strcmp(pkgarch, "all") == 0)
+	    continue;
 	 if(debug_autoremove)
 	 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.str(string(""));
-	 ostr << "Package: " << pkg.Name() 
+	 ostr << "Package: " << pkg.Name()
+	      << "\nArchitecture: " << pkgarch
 	      << "\nAuto-Installed: 1\n\n";
 	      << "\nAuto-Installed: 1\n\n";
 	 fprintf(OutFile,"%s",ostr.str().c_str());
 	 fprintf(OutFile,"%s",ostr.str().c_str());
-	 fprintf(OutFile,"\n");
       }
       }
    }
    }
    fclose(OutFile);
    fclose(OutFile);
@@ -613,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		/*{{{*/
 // DepCache::Update - Figure out all the state information		/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* This will figure out the state of all the packages and all the 
 /* This will figure out the state of all the packages and all the 
@@ -626,9 +749,13 @@ void pkgDepCache::Update(OpProgress *Prog)
    iKeepCount = 0;
    iKeepCount = 0;
    iBrokenCount = 0;
    iBrokenCount = 0;
    iBadCount = 0;
    iBadCount = 0;
-   
+
+   std::set<unsigned long> recheck;
+
    // Perform the depends pass
    // Perform the depends pass
    int Done = 0;
    int Done = 0;
+   bool const checkMultiArch = APT::Configuration::getArchitectures().size() > 1;
+   unsigned long killed = 0;
    for (PkgIterator I = PkgBegin(); I.end() != true; I++,Done++)
    for (PkgIterator I = PkgBegin(); I.end() != true; I++,Done++)
    {
    {
       if (Prog != 0 && Done%20 == 0)
       if (Prog != 0 && Done%20 == 0)
@@ -636,7 +763,7 @@ void pkgDepCache::Update(OpProgress *Prog)
       for (VerIterator V = I.VersionList(); V.end() != true; V++)
       for (VerIterator V = I.VersionList(); V.end() != true; V++)
       {
       {
 	 unsigned char Group = 0;
 	 unsigned char Group = 0;
-	 
+
 	 for (DepIterator D = V.DependsList(); D.end() != true; D++)
 	 for (DepIterator D = V.DependsList(); D.end() != true; D++)
 	 {
 	 {
 	    // Build the dependency state.
 	    // Build the dependency state.
@@ -654,16 +781,105 @@ void pkgDepCache::Update(OpProgress *Prog)
 		D->Type == Dep::DpkgBreaks ||
 		D->Type == Dep::DpkgBreaks ||
 		D->Type == Dep::Obsoletes)
 		D->Type == Dep::Obsoletes)
 	       State = ~State;
 	       State = ~State;
-	 }	 
+	 }
       }
       }
 
 
-      // Compute the pacakge dependency state and size additions
+      // Compute the package dependency state and size additions
       AddSizes(I);
       AddSizes(I);
       UpdateVerState(I);
       UpdateVerState(I);
       AddStates(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);
       Prog->Progress(Done);
 
 
    readStateFile(Prog);
    readStateFile(Prog);
@@ -830,6 +1046,10 @@ void pkgDepCache::MarkDelete(PkgIterator const &Pkg, bool rPurge,
    AddStates(Pkg);   
    AddStates(Pkg);   
    Update(Pkg);
    Update(Pkg);
    AddSizes(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	/*{{{*/
 // DepCache::IsDeleteOk - check if it is ok to remove this package	/*{{{*/
@@ -1356,7 +1576,7 @@ bool pkgDepCache::MarkRequired(InRootSetFunc &userFunc)
 
 
       // debug output
       // debug output
       if(debug_autoremove && PkgState[p->ID].Flags & Flag::Auto)
       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
    // init vars
@@ -1390,13 +1610,18 @@ bool pkgDepCache::MarkRequired(InRootSetFunc &userFunc)
 // MarkPackage - mark a single package in Mark-and-Sweep		/*{{{*/
 // MarkPackage - mark a single package in Mark-and-Sweep		/*{{{*/
 void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
 void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
 			      const pkgCache::VerIterator &ver,
 			      const pkgCache::VerIterator &ver,
-			      bool follow_recommends,
-			      bool follow_suggests)
+			      bool const &follow_recommends,
+			      bool const &follow_suggests)
 {
 {
    pkgDepCache::StateCache &state = PkgState[pkg->ID];
    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 0
    // If a package was garbage-collected but is now being marked, we
    // If a package was garbage-collected but is now being marked, we
@@ -1422,15 +1647,11 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
       !(ver == currver && instver.end() && !ver.end()))
       !(ver == currver && instver.end() && !ver.end()))
       return;
       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)
    if(debug_autoremove)
      {
      {
-       std::clog << "Marking: " << pkg.Name();
+       std::clog << "Marking: " << pkg.FullName();
        if(!ver.end())
        if(!ver.end())
 	 std::clog << " " << ver.VerStr();
 	 std::clog << " " << ver.VerStr();
        if(!currver.end())
        if(!currver.end())
@@ -1442,8 +1663,34 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
 
 
    state.Marked=true;
    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)
      for(DepIterator d = ver.DependsList(); !d.end(); ++d)
      {
      {
 	if(d->Type == Dep::Depends ||
 	if(d->Type == Dep::Depends ||
@@ -1461,10 +1708,9 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
 	      {
 	      {
 		if(debug_autoremove)
 		if(debug_autoremove)
 		  {
 		  {
-		    std::clog << "Following dep: " << d.ParentPkg().Name()
+		    std::clog << "Following dep: " << d.ParentPkg().FullName()
 			      << " " << d.ParentVer().VerStr() << " "
 			      << " " << d.ParentVer().VerStr() << " "
-			      << d.DepType() << " "
-			      << d.TargetPkg().Name();
+			      << d.DepType() << " " << d.TargetPkg().FullName();
 		    if((d->CompareOp & ~pkgCache::Dep::Or) != pkgCache::Dep::NoOp)
 		    if((d->CompareOp & ~pkgCache::Dep::Or) != pkgCache::Dep::NoOp)
 		      {
 		      {
 			std::clog << " (" << d.CompType() << " "
 			std::clog << " (" << d.CompType() << " "
@@ -1472,7 +1718,7 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
 		      }
 		      }
 		    std::clog << std::endl;
 		    std::clog << std::endl;
 		  }
 		  }
-		 MarkPackage(V.ParentPkg(), V, 
+		 MarkPackage(V.ParentPkg(), V,
 			     follow_recommends, follow_suggests);
 			     follow_recommends, follow_suggests);
 	      }
 	      }
 	   }
 	   }
@@ -1485,17 +1731,16 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
 	      {
 	      {
 		if(debug_autoremove)
 		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)
 		    if((d->CompareOp & ~pkgCache::Dep::Or) != pkgCache::Dep::NoOp)
 		      {
 		      {
 			std::clog << " (" << d.CompType() << " "
 			std::clog << " (" << d.CompType() << " "
 				  << d.TargetVer() << ")";
 				  << d.TargetVer() << ")";
 		      }
 		      }
 		    std::clog << ", provided by "
 		    std::clog << ", provided by "
-			      << prv.OwnerPkg().Name() << " "
+			      << prv.OwnerPkg().FullName() << " "
 			      << prv.OwnerVer().VerStr()
 			      << prv.OwnerVer().VerStr()
 			      << std::endl;
 			      << std::endl;
 		  }
 		  }
@@ -1506,7 +1751,6 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
 	   }
 	   }
 	}
 	}
      }
      }
-   }
 }
 }
 									/*}}}*/
 									/*}}}*/
 bool pkgDepCache::Sweep()						/*{{{*/
 bool pkgDepCache::Sweep()						/*{{{*/
@@ -1528,7 +1772,7 @@ bool pkgDepCache::Sweep()						/*{{{*/
      {
      {
 	state.Garbage=true;
 	state.Garbage=true;
 	if(debug_autoremove)
 	if(debug_autoremove)
-	   std::cout << "Garbage: " << p.Name() << std::endl;
+	   std::cout << "Garbage: " << p.FullName() << std::endl;
      }
      }
   }   
   }   
 
 

+ 12 - 6
apt-pkg/depcache.h

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

+ 2 - 2
apt-pkg/metaindex.h

@@ -33,8 +33,8 @@ class metaIndex
    virtual const char* GetType() const {return Type;}
    virtual const char* GetType() const {return Type;}
 
 
    // Interface for acquire
    // 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 vector<pkgIndexFile *> *GetIndexFiles() = 0; 
    virtual bool IsTrusted() const = 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)
    if (FileList[Pkg->ID].empty() == false)
       return 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;
    return true;
 }
 }
 									/*}}}*/
 									/*}}}*/
@@ -199,7 +204,7 @@ bool pkgOrderList::OrderCritical()
       {
       {
 	 PkgIterator P(Cache,*I);
 	 PkgIterator P(Cache,*I);
 	 if (IsNow(P) == true)
 	 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);
 	 PkgIterator P(Cache,*I);
 	 if (IsNow(P) == true)
 	 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)
    if (Debug == true)
    {
    {
       for (int j = 0; j != Depth; j++) clog << ' ';
       for (int j = 0; j != Depth; j++) clog << ' ';
-      clog << "Visit " << Pkg.Name() << endl;
+      clog << "Visit " << Pkg.FullName() << endl;
    }
    }
    
    
    Depth++;
    Depth++;
@@ -602,7 +607,7 @@ bool pkgOrderList::VisitNode(PkgIterator Pkg)
    if (Debug == true)
    if (Debug == true)
    {
    {
       for (int j = 0; j != Depth; j++) clog << ' ';
       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;
    return true;

+ 24 - 8
apt-pkg/packagemanager.cc

@@ -80,7 +80,10 @@ bool pkgPackageManager::GetArchives(pkgAcquire *Owner,pkgSourceList *Sources,
       // Skip already processed packages
       // Skip already processed packages
       if (List->IsNow(Pkg) == false)
       if (List->IsNow(Pkg) == false)
 	 continue;
 	 continue;
-	 
+
+      if (pkgCache::VerIterator(Cache, Cache[Pkg].CandidateVer).Pseudo() == true)
+	 continue;
+
       new pkgAcqArchive(Owner,Sources,Recs,Cache[Pkg].InstVerIter(Cache),
       new pkgAcqArchive(Owner,Sources,Recs,Cache[Pkg].InstVerIter(Cache),
 			FileNames[Pkg->ID]);
 			FileNames[Pkg->ID]);
    }
    }
@@ -277,8 +280,10 @@ bool pkgPackageManager::ConfigureAll()
    for (pkgOrderList::iterator I = OList.begin(); I != OList.end(); I++)
    for (pkgOrderList::iterator I = OList.begin(); I != OList.end(); I++)
    {
    {
       PkgIterator Pkg(Cache,*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;
 	 return false;
       
       
       List->Flag(Pkg,pkgOrderList::Configured,pkgOrderList::States);
       List->Flag(Pkg,pkgOrderList::Configured,pkgOrderList::States);
@@ -313,7 +318,9 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg)
    {
    {
       PkgIterator Pkg(Cache,*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;
 	 return false;
       
       
       List->Flag(Pkg,pkgOrderList::Configured,pkgOrderList::States);
       List->Flag(Pkg,pkgOrderList::Configured,pkgOrderList::States);
@@ -460,7 +467,12 @@ bool pkgPackageManager::SmartRemove(PkgIterator Pkg)
       return true;
       return true;
 
 
    List->Flag(Pkg,pkgOrderList::Configured,pkgOrderList::States);
    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					/*{{{*/
 // PM::SmartUnPack - Install helper					/*{{{*/
@@ -574,10 +586,14 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg)
    for (PrvIterator P = Cache[Pkg].InstVerIter(Cache).ProvidesList(); 
    for (PrvIterator P = Cache[Pkg].InstVerIter(Cache).ProvidesList(); 
 	P.end() == false; P++)
 	P.end() == false; P++)
       CheckRConflicts(Pkg,P.ParentPkg().RevDependsList(),P.ProvideVersion());
       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;
       return false;
-   
+
    List->Flag(Pkg,pkgOrderList::UnPacked,pkgOrderList::States);
    List->Flag(Pkg,pkgOrderList::UnPacked,pkgOrderList::States);
    
    
    // Perform immedate configuration of the package.
    // Perform immedate configuration of the package.

+ 206 - 41
apt-pkg/pkgcache.cc

@@ -79,7 +79,8 @@ pkgCache::Header::Header()
    StringList = 0;
    StringList = 0;
    VerSysName = 0;
    VerSysName = 0;
    Architecture = 0;
    Architecture = 0;
-   memset(HashTable,0,sizeof(HashTable));
+   memset(PkgHashTable,0,sizeof(PkgHashTable));
+   memset(GrpHashTable,0,sizeof(GrpHashTable));
    memset(Pools,0,sizeof(Pools));
    memset(Pools,0,sizeof(Pools));
 }
 }
 									/*}}}*/
 									/*}}}*/
@@ -107,6 +108,7 @@ bool pkgCache::Header::CheckSizes(Header &Against) const
 /* */
 /* */
 pkgCache::pkgCache(MMap *Map, bool DoMap) : Map(*Map)
 pkgCache::pkgCache(MMap *Map, bool DoMap) : Map(*Map)
 {
 {
+   MultiArchEnabled = APT::Configuration::getArchitectures().size() > 1;
    if (DoMap == true)
    if (DoMap == true)
       ReMap();
       ReMap();
 }
 }
@@ -118,6 +120,7 @@ bool pkgCache::ReMap()
 {
 {
    // Apply the typecasts.
    // Apply the typecasts.
    HeaderP = (Header *)Map.Data();
    HeaderP = (Header *)Map.Data();
+   GrpP = (Group *)Map.Data();
    PkgP = (Package *)Map.Data();
    PkgP = (Package *)Map.Data();
    VerFileP = (VerFile *)Map.Data();
    VerFileP = (VerFile *)Map.Data();
    DescFileP = (DescFile *)Map.Data();
    DescFileP = (DescFile *)Map.Data();
@@ -165,7 +168,7 @@ unsigned long pkgCache::sHash(const string &Str) const
    unsigned long Hash = 0;
    unsigned long Hash = 0;
    for (string::const_iterator I = Str.begin(); I != Str.end(); I++)
    for (string::const_iterator I = Str.begin(); I != Str.end(); I++)
       Hash = 5*Hash + tolower_ascii(*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
 unsigned long pkgCache::sHash(const char *Str) const
@@ -173,26 +176,82 @@ unsigned long pkgCache::sHash(const char *Str) const
    unsigned long Hash = 0;
    unsigned long Hash = 0;
    for (const char *I = Str; *I != 0; I++)
    for (const char *I = Str; *I != 0; I++)
       Hash = 5*Hash + tolower_ascii(*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
    // 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)
    for (; Pkg != PkgP; Pkg = PkgP + Pkg->NextPackage)
    {
    {
       if (Pkg->Name != 0 && StrP[Pkg->Name] == Name[0] &&
       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);
    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	/*{{{*/
 // Cache::CompTypeDeb - Return a string describing the compare type	/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* This returns a string representation of the dependency compare 
 /* This returns a string representation of the dependency compare 
@@ -242,11 +301,84 @@ const char *pkgCache::Priority(unsigned char Prio)
    return 0;
    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 list of packages includes
+   "package noise" (= packages with the same hash value but different name) */
+pkgCache::PkgIterator pkgCache::GrpIterator::NextPkg(pkgCache::PkgIterator const &LastPkg) {
+	if (unlikely(IsGood() == false || S->FirstPackage == 0 ||
+	    LastPkg.end() == true))
+		return PkgIterator(*Owner, 0);
+
+	// Iterate over the list to find the next package
+	pkgCache::Package *Pkg = Owner->PkgP + LastPkg.Index();
+	Pkg = Owner->PkgP + Pkg->NextPackage;
+	for (; Pkg != Owner->PkgP; Pkg = Owner->PkgP + Pkg->NextPackage) {
+		if (S->Name == Pkg->Name)
+			return PkgIterator(*Owner, Pkg);
+		if ((Owner->PkgP + S->LastPackage) == Pkg)
+			break;
+	}
+
+	return PkgIterator(*Owner, 0);
+}
+									/*}}}*/
+// 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				/*{{{*/
 // PkgIterator::operator ++ - Postfix incr				/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
@@ -254,14 +386,14 @@ void pkgCache::DescIterator::_dummy() {}
 void pkgCache::PkgIterator::operator ++(int) 
 void pkgCache::PkgIterator::operator ++(int) 
 {
 {
    // Follow the current links
    // 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
    // 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++;
       HashIndex++;
-      Pkg = Owner->PkgP + Owner->HeaderP->HashTable[HashIndex];
+      S = Owner->PkgP + Owner->HeaderP->PkgHashTable[HashIndex];
    }
    }
 };
 };
 									/*}}}*/
 									/*}}}*/
@@ -270,12 +402,12 @@ void pkgCache::PkgIterator::operator ++(int)
 /* By this we mean if it is either cleanly installed or cleanly removed. */
 /* By this we mean if it is either cleanly installed or cleanly removed. */
 pkgCache::PkgIterator::OkState pkgCache::PkgIterator::State() const
 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;
       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
       // we leave triggers alone complettely. dpkg deals with
       // them in a hard-to-predict manner and if they get 
       // them in a hard-to-predict manner and if they get 
       // resolved by dpkg before apt run dpkg --configure on 
       // resolved by dpkg before apt run dpkg --configure on 
@@ -284,8 +416,8 @@ pkgCache::PkgIterator::OkState pkgCache::PkgIterator::State() const
       //Pkg->CurrentState == pkgCache::State::TriggersPending)
       //Pkg->CurrentState == pkgCache::State::TriggersPending)
       return NeedsConfigure;
       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 NeedsUnpack;
       
       
    return NeedsNothing;
    return NeedsNothing;
@@ -332,7 +464,7 @@ operator<<(ostream& out, pkgCache::PkgIterator Pkg)
    string candidate = string(Pkg.CandVersion() == 0 ? "none" : Pkg.CandVersion());
    string candidate = string(Pkg.CandVersion() == 0 ? "none" : Pkg.CandVersion());
    string newest = string(Pkg.VersionList().end() ? "none" : Pkg.VersionList().VerStr());
    string newest = string(Pkg.VersionList().end() ? "none" : Pkg.VersionList().VerStr());
 
 
-   out << Pkg.Name() << " < " << current;
+   out << Pkg.Name() << " [ " << Pkg.Arch() << " ] < " << current;
    if (current != candidate)
    if (current != candidate)
       out << " -> " << candidate;
       out << " -> " << candidate;
    if ( newest != "none" && candidate != newest)
    if ( newest != "none" && candidate != newest)
@@ -341,17 +473,29 @@ operator<<(ostream& out, pkgCache::PkgIterator Pkg)
    return out;
    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	/*{{{*/
 // DepIterator::IsCritical - Returns true if the dep is important	/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* Currently critical deps are defined as depends, predepends and
 /* Currently critical deps are defined as depends, predepends and
    conflicts (including dpkg's Breaks fields). */
    conflicts (including dpkg's Breaks fields). */
 bool pkgCache::DepIterator::IsCritical()
 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 true;
    return false;
    return false;
 }
 }
@@ -430,12 +574,12 @@ pkgCache::Version **pkgCache::DepIterator::AllTargets()
       // Walk along the actual package providing versions
       // Walk along the actual package providing versions
       for (VerIterator I = DPkg.VersionList(); I.end() == false; I++)
       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;
 	    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())
 	     ParentPkg() == I.ParentPkg())
 	    continue;
 	    continue;
 	 
 	 
@@ -447,12 +591,12 @@ pkgCache::Version **pkgCache::DepIterator::AllTargets()
       // Follow all provides
       // Follow all provides
       for (PrvIterator I = DPkg.ProvidesList(); I.end() == false; I++)
       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;
 	    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())
 	     ParentPkg() == I.OwnerPkg())
 	    continue;
 	    continue;
 	 
 	 
@@ -490,7 +634,7 @@ void pkgCache::DepIterator::GlobOr(DepIterator &Start,DepIterator &End)
    End = *this;
    End = *this;
    for (bool LastOR = true; end() == false && LastOR == true;)
    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)++;
       (*this)++;
       if (LastOR == true)
       if (LastOR == true)
 	 End = (*this);
 	 End = (*this);
@@ -545,6 +689,23 @@ bool pkgCache::VerIterator::Automatic() const
    return false;
    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	/*{{{*/
 // VerIterator::NewestFile - Return the newest file version relation	/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* This looks at the version numbers associated with all of the sources
 /* This looks at the version numbers associated with all of the sources
@@ -625,7 +786,9 @@ string pkgCache::VerIterator::RelStr()
 	 else
 	 else
 	    Res += File.Site();
 	    Res += File.Site();
       }      
       }      
-   }   
+   }
+   if (S->ParentPkg != 0)
+      Res.append(" [").append(Arch()).append("]");
    return Res;
    return Res;
 }
 }
 									/*}}}*/
 									/*}}}*/
@@ -640,7 +803,7 @@ bool pkgCache::PkgFileIterator::IsOk()
    if (stat(FileName(),&Buf) != 0)
    if (stat(FileName(),&Buf) != 0)
       return false;
       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 false;
 
 
    return true;
    return true;
@@ -664,6 +827,8 @@ string pkgCache::PkgFileIterator::RelStr()
       Res = Res + (Res.empty() == true?"l=":",l=")  + Label();
       Res = Res + (Res.empty() == true?"l=":",l=")  + Label();
    if (Component() != 0)
    if (Component() != 0)
       Res = Res + (Res.empty() == true?"c=":",c=")  + Component();
       Res = Res + (Res.empty() == true?"c=":",c=")  + Component();
+   if (Architecture() != 0)
+      Res = Res + (Res.empty() == true?"b=":",b=")  + Architecture();
    return Res;
    return Res;
 }
 }
 									/*}}}*/
 									/*}}}*/

+ 40 - 14
apt-pkg/pkgcache.h

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

+ 209 - 56
apt-pkg/pkgcachegen.cc

@@ -18,6 +18,7 @@
 #include <apt-pkg/progress.h>
 #include <apt-pkg/progress.h>
 #include <apt-pkg/sourcelist.h>
 #include <apt-pkg/sourcelist.h>
 #include <apt-pkg/configuration.h>
 #include <apt-pkg/configuration.h>
+#include <apt-pkg/aptconfiguration.h>
 #include <apt-pkg/strutl.h>
 #include <apt-pkg/strutl.h>
 #include <apt-pkg/sptr.h>
 #include <apt-pkg/sptr.h>
 #include <apt-pkg/pkgsystem.h>
 #include <apt-pkg/pkgsystem.h>
@@ -38,7 +39,7 @@ typedef vector<pkgIndexFile *>::iterator FileIterator;
 
 
 // CacheGenerator::pkgCacheGenerator - Constructor			/*{{{*/
 // 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) :
 pkgCacheGenerator::pkgCacheGenerator(DynamicMMap *pMap,OpProgress *Prog) :
 		    Map(*pMap), Cache(pMap,false), Progress(Prog),
 		    Map(*pMap), Cache(pMap,false), Progress(Prog),
 		    FoundFileDeps(0)
 		    FoundFileDeps(0)
@@ -107,13 +108,26 @@ bool pkgCacheGenerator::MergeList(ListParser &List,
    unsigned int Counter = 0;
    unsigned int Counter = 0;
    while (List.Step() == true)
    while (List.Step() == true)
    {
    {
-      // Get a pointer to the package structure
-      string PackageName = List.Package();
+      string const PackageName = List.Package();
       if (PackageName.empty() == true)
       if (PackageName.empty() == true)
 	 return false;
 	 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;
       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());
 	 return _error->Error(_("Error occurred while processing %s (NewPackage)"),PackageName.c_str());
       Counter++;
       Counter++;
       if (Counter % 100 == 0 && Progress != 0)
       if (Counter % 100 == 0 && Progress != 0)
@@ -250,6 +264,7 @@ bool pkgCacheGenerator::MergeList(ListParser &List,
 
 
       if ((*LastDesc == 0 && _error->PendingError()) || NewFileDesc(Desc,List) == false)
       if ((*LastDesc == 0 && _error->PendingError()) || NewFileDesc(Desc,List) == false)
 	 return _error->Error(_("Error occurred while processing %s (NewFileDesc2)"),PackageName.c_str());
 	 return _error->Error(_("Error occurred while processing %s (NewFileDesc2)"),PackageName.c_str());
+      }
    }
    }
 
 
    FoundFileDeps |= List.HasFileDeps();
    FoundFileDeps |= List.HasFileDeps();
@@ -317,33 +332,71 @@ bool pkgCacheGenerator::MergeFileProvides(ListParser &List)
    return true;
    return true;
 }
 }
 									/*}}}*/
 									/*}}}*/
+// CacheGenerator::NewGroup - Add a new group				/*{{{*/
+// ---------------------------------------------------------------------
+/* This creates a new group structure and adds it to the hash table */
+bool pkgCacheGenerator::NewGroup(pkgCache::GrpIterator &Grp, const string &Name) {
+	Grp = Cache.FindGrp(Name);
+	if (Grp.end() == false)
+		return true;
+
+	// Get a structure
+	unsigned long const Group = Map.Allocate(sizeof(pkgCache::Group));
+	if (unlikely(Group == 0))
+		return false;
+
+	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 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			/*{{{*/
 // CacheGenerator::NewPackage - Add a new package			/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* This creates a new package structure and adds it to the hash table */
 /* This creates a new package structure and adds it to the hash table */
-bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator &Pkg,const string &Name)
-{
-   Pkg = Cache.FindPkg(Name);
-   if (Pkg.end() == false)
-      return true;
+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
    // Get a structure
-   unsigned long Package = Map.Allocate(sizeof(pkgCache::Package));
-   if (Package == 0)
+   unsigned long const Package = Map.Allocate(sizeof(pkgCache::Package));
+   if (unlikely(Package == 0))
       return false;
       return false;
-   
    Pkg = pkgCache::PkgIterator(Cache,Cache.PkgP + Package);
    Pkg = pkgCache::PkgIterator(Cache,Cache.PkgP + Package);
-   
+
    // Insert it into the hash table
    // 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);
+   Pkg->NextPackage = Cache.HeaderP->PkgHashTable[Hash];
+   Cache.HeaderP->PkgHashTable[Hash] = Package;
+
+   // remember the packages in the group
+   Grp->FirstPackage = Package;
+   if (Grp->LastPackage == 0)
+      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;
       return false;
    Pkg->ID = Cache.HeaderP->PackageCount++;
    Pkg->ID = Cache.HeaderP->PackageCount++;
-   
+
    return true;
    return true;
 }
 }
 									/*}}}*/
 									/*}}}*/
@@ -462,21 +515,87 @@ map_ptrloc pkgCacheGenerator::NewDescription(pkgCache::DescIterator &Desc,
    return Description;
    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
 /* This creates a dependency element in the tree. It is linked to the
    version and to the package that it is pointing to. */
    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
    // 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;
       return false;
    
    
    // Fill it in
    // Fill it in
@@ -485,12 +604,7 @@ bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver,
    Dep->Type = Type;
    Dep->Type = Type;
    Dep->CompareOp = Op;
    Dep->CompareOp = Op;
    Dep->ID = Cache.HeaderP->DependsCount++;
    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
    // Probe the reverse dependency list for a version string that matches
    if (Version.empty() == false)
    if (Version.empty() == false)
    {
    {
@@ -498,29 +612,23 @@ bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver,
 	 if (I->Version != 0 && I.TargetVer() == Version)
 	 if (I->Version != 0 && I.TargetVer() == Version)
 	    Dep->Version = I->Version;*/
 	    Dep->Version = I->Version;*/
       if (Dep->Version == 0)
       if (Dep->Version == 0)
-	 if ((Dep->Version = WriteString(Version)) == 0)
+	 if (unlikely((Dep->Version = Map.WriteString(Version)) == 0))
 	    return false;
 	    return false;
    }
    }
-      
+
    // Link it to the package
    // Link it to the package
    Dep->Package = Pkg.Index();
    Dep->Package = Pkg.Index();
    Dep->NextRevDepends = Pkg->RevDepends;
    Dep->NextRevDepends = Pkg->RevDepends;
    Pkg->RevDepends = Dep.Index();
    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;
       OldDepLast = &Ver->DependsList;
       for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; D++)
       for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; D++)
 	 OldDepLast = &D->NextDepends;
 	 OldDepLast = &D->NextDepends;
-      OldDepVer = Ver;
    }
    }
 
 
-   // Is it a file dependency?
-   if (PackageName[0] == '/')
-      FoundFileDeps = true;
-   
    Dep->NextDepends = *OldDepLast;
    Dep->NextDepends = *OldDepLast;
    *OldDepLast = Dep.Index();
    *OldDepLast = Dep.Index();
    OldDepLast = &Dep->NextDepends;
    OldDepLast = &Dep->NextDepends;
@@ -528,22 +636,58 @@ bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver,
    return true;
    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			/*{{{*/
 // ListParser::NewProvides - Create a Provides element			/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* */
 /* */
 bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver,
 bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver,
-					        const string &PackageName,
+					        const string &PkgName,
+						const string &PkgArch,
 						const string &Version)
 						const string &Version)
 {
 {
    pkgCache &Cache = Owner->Cache;
    pkgCache &Cache = Owner->Cache;
 
 
    // We do not add self referencing provides
    // We do not add self referencing provides
-   if (Ver.ParentPkg().Name() == PackageName)
+   if (Ver.ParentPkg().Name() == PkgName && PkgArch == Ver.Arch(true))
       return true;
       return true;
    
    
    // Get a structure
    // 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;
       return false;
    Cache.HeaderP->ProvidesCount++;
    Cache.HeaderP->ProvidesCount++;
    
    
@@ -552,12 +696,12 @@ bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver,
    Prv->Version = Ver.Index();
    Prv->Version = Ver.Index();
    Prv->NextPkgProv = Ver->ProvidesList;
    Prv->NextPkgProv = Ver->ProvidesList;
    Ver->ProvidesList = Prv.Index();
    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;
       return false;
    
    
    // Locate the target package
    // Locate the target package
    pkgCache::PkgIterator Pkg;
    pkgCache::PkgIterator Pkg;
-   if (Owner->NewPackage(Pkg,PackageName) == false)
+   if (unlikely(Owner->NewPackage(Pkg,PkgName, PkgArch) == false))
       return false;
       return false;
    
    
    // Link it to the package
    // Link it to the package
@@ -917,6 +1061,9 @@ bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress,
       if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
       if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
 		     Files.begin()+EndOfSource,Files.end()) == false)
 		     Files.begin()+EndOfSource,Files.end()) == false)
 	 return false;
 	 return false;
+
+      // FIXME: move me to a better place
+      Gen.FinishCache(Progress);
    }
    }
    else
    else
    {
    {
@@ -959,6 +1106,9 @@ bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress,
       if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
       if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
 		     Files.begin()+EndOfSource,Files.end()) == false)
 		     Files.begin()+EndOfSource,Files.end()) == false)
 	 return false;
 	 return false;
+
+      // FIXME: move me to a better place
+      Gen.FinishCache(Progress);
    }
    }
    if (Debug == true)
    if (Debug == true)
       std::clog << "Caches are ready for shipping" << std::endl;
       std::clog << "Caches are ready for shipping" << std::endl;
@@ -1006,7 +1156,10 @@ bool pkgMakeOnlyStatusCache(OpProgress &Progress,DynamicMMap **OutMap)
    if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
    if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
 		  Files.begin()+EndOfSource,Files.end()) == false)
 		  Files.begin()+EndOfSource,Files.end()) == false)
       return false;
       return false;
-   
+
+   // FIXME: move me to a better place
+   Gen.FinishCache(Progress);
+
    if (_error->PendingError() == true)
    if (_error->PendingError() == true)
       return false;
       return false;
    *OutMap = Map.UnGuard();
    *OutMap = Map.UnGuard();

+ 12 - 5
apt-pkg/pkgcachegen.h

@@ -51,9 +51,13 @@ class pkgCacheGenerator							/*{{{*/
    // Flag file dependencies
    // Flag file dependencies
    bool FoundFileDeps;
    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 NewFileVer(pkgCache::VerIterator &Ver,ListParser &List);
    bool NewFileDesc(pkgCache::DescIterator &Desc,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);
    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);
    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 HasFileDeps() {return FoundFileDeps;};
    bool MergeFileProvides(ListParser &List);
    bool MergeFileProvides(ListParser &List);
-      
+   bool FinishCache(OpProgress &Progress);
+
    pkgCacheGenerator(DynamicMMap *Map,OpProgress *Progress);
    pkgCacheGenerator(DynamicMMap *Map,OpProgress *Progress);
    ~pkgCacheGenerator();
    ~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 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 string &S) {return Owner->Map.WriteString(S);};
    inline unsigned long WriteString(const char *S,unsigned int Size) {return Owner->Map.WriteString(S,Size);};
    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,
 		   const string &Version,unsigned int Op,
 		   unsigned int Type);
 		   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:
    public:
    
    
    // These all operate against the current section
    // These all operate against the current section
    virtual string Package() = 0;
    virtual string Package() = 0;
+   virtual string Architecture() = 0;
+   virtual bool ArchitectureAll() = 0;
    virtual string Version() = 0;
    virtual string Version() = 0;
    virtual bool NewVersion(pkgCache::VerIterator Ver) = 0;
    virtual bool NewVersion(pkgCache::VerIterator Ver) = 0;
    virtual string Description() = 0;
    virtual string Description() = 0;

+ 22 - 19
apt-pkg/policy.cc

@@ -187,35 +187,38 @@ pkgCache::VerIterator pkgPolicy::GetCandidateVer(pkgCache::PkgIterator Pkg)
 void pkgPolicy::CreatePin(pkgVersionMatch::MatchType Type,string Name,
 void pkgPolicy::CreatePin(pkgVersionMatch::MatchType Type,string Name,
 			  string Data,signed short Priority)
 			  string Data,signed short Priority)
 {
 {
-   Pin *P = 0;
-   
    if (Name.empty() == true)
    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
 	 // Check the unmatched table
-	 for (vector<PkgPin>::iterator I = Unmatched.begin(); 
+	 for (vector<PkgPin>::iterator I = Unmatched.begin();
 	      I != Unmatched.end() && P == 0; I++)
 	      I != Unmatched.end() && P == 0; I++)
 	    if (I->Pkg == Name)
 	    if (I->Pkg == Name)
 	       P = &*I;
 	       P = &*I;
-	 
+
 	 if (P == 0)
 	 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	/*{{{*/
 // 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. */
    Weird types may override this. */
 bool pkgSourceList::Type::ParseLine(vector<metaIndex *> &List,
 bool pkgSourceList::Type::ParseLine(vector<metaIndex *> &List,
 				    const char *Buffer,
 				    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 URI;
    string Dist;
    string Dist;
-   string Section;   
-   
+   string Section;
+
    if (ParseQuoteWord(Buffer,URI) == false)
    if (ParseQuoteWord(Buffer,URI) == false)
       return _error->Error(_("Malformed line %lu in source list %s (URI)"),CurLine,File.c_str());
       return _error->Error(_("Malformed line %lu in source list %s (URI)"),CurLine,File.c_str());
    if (ParseQuoteWord(Buffer,Dist) == false)
    if (ParseQuoteWord(Buffer,Dist) == false)
@@ -93,7 +131,7 @@ bool pkgSourceList::Type::ParseLine(vector<metaIndex *> &List,
       if (ParseQuoteWord(Buffer,Section) == true)
       if (ParseQuoteWord(Buffer,Section) == true)
 	 return _error->Error(_("Malformed line %lu in source list %s (absolute dist)"),CurLine,File.c_str());
 	 return _error->Error(_("Malformed line %lu in source list %s (absolute dist)"),CurLine,File.c_str());
       Dist = SubstVar(Dist,"$(ARCH)",_config->Find("APT::Architecture"));
       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
    // Grab the rest of the dists
@@ -102,7 +140,7 @@ bool pkgSourceList::Type::ParseLine(vector<metaIndex *> &List,
    
    
    do
    do
    {
    {
-      if (CreateItem(List,URI,Dist,Section) == false)
+      if (CreateItem(List, URI, Dist, Section, Options) == false)
 	 return false;
 	 return false;
    }
    }
    while (ParseQuoteWord(Buffer,Section) == true);
    while (ParseQuoteWord(Buffer,Section) == true);
@@ -239,36 +277,7 @@ bool pkgSourceList::ReadAppend(string File)
       if (Parse == 0)
       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());
 	 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 false;
    }
    }
    return true;
    return true;

+ 5 - 3
apt-pkg/sourcelist.h

@@ -29,6 +29,7 @@
 
 
 #include <string>
 #include <string>
 #include <vector>
 #include <vector>
+#include <map>
 #include <apt-pkg/pkgcache.h>
 #include <apt-pkg/pkgcache.h>
 #include <apt-pkg/metaindex.h>
 #include <apt-pkg/metaindex.h>
 
 
@@ -57,9 +58,10 @@ class pkgSourceList
       bool FixupURI(string &URI) const;
       bool FixupURI(string &URI) const;
       virtual bool ParseLine(vector<metaIndex *> &List,
       virtual bool ParseLine(vector<metaIndex *> &List,
 			     const char *Buffer,
 			     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();
       Type();
       virtual ~Type() {};
       virtual ~Type() {};
    };
    };

+ 7 - 1
apt-pkg/versionmatch.cc

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

+ 2 - 0
apt-pkg/versionmatch.h

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

+ 57 - 42
cmdline/apt-cache.cc

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

+ 48 - 38
cmdline/apt-get.cc

@@ -258,8 +258,8 @@ void ShowBroken(ostream &out,CacheFile &Cache,bool Now)
       }
       }
       
       
       // Print out each package and the failed dependencies
       // 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;
       bool First = true;
       pkgCache::VerIterator Ver;
       pkgCache::VerIterator Ver;
       
       
@@ -312,7 +312,7 @@ void ShowBroken(ostream &out,CacheFile &Cache,bool Now)
 	       out << ' ' << End.DepType() << ": ";
 	       out << ' ' << End.DepType() << ": ";
 	    FirstOr = false;
 	    FirstOr = false;
 	    
 	    
-	    out << Start.TargetPkg().Name();
+	    out << Start.TargetPkg().FullName(true);
 	 
 	 
 	    // Show a quick summary of the version requirements
 	    // Show a quick summary of the version requirements
 	    if (Start.TargetVer() != 0)
 	    if (Start.TargetVer() != 0)
@@ -374,7 +374,9 @@ void ShowNew(ostream &out,CacheFile &Cache)
    {
    {
       pkgCache::PkgIterator I(Cache,Cache.List[J]);
       pkgCache::PkgIterator I(Cache,Cache.List[J]);
       if (Cache[I].NewInstall() == true) {
       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";
          VersionsList += string(Cache[I].CandVersion) + "\n";
       }
       }
    }
    }
@@ -396,10 +398,12 @@ void ShowDel(ostream &out,CacheFile &Cache)
       pkgCache::PkgIterator I(Cache,Cache.List[J]);
       pkgCache::PkgIterator I(Cache,Cache.List[J]);
       if (Cache[I].Delete() == true)
       if (Cache[I].Delete() == true)
       {
       {
+	 if (Cache[I].CandidateVerIter(Cache).Pseudo() == true)
+	    continue;
 	 if ((Cache[I].iFlags & pkgDepCache::Purge) == pkgDepCache::Purge)
 	 if ((Cache[I].iFlags & pkgDepCache::Purge) == pkgDepCache::Purge)
-	    List += string(I.Name()) + "* ";
+	    List += I.FullName(true) + "* ";
 	 else
 	 else
-	    List += string(I.Name()) + " ";
+	    List += I.FullName(true) + " ";
      
      
      VersionsList += string(Cache[I].CandVersion)+ "\n";
      VersionsList += string(Cache[I].CandVersion)+ "\n";
       }
       }
@@ -424,7 +428,7 @@ void ShowKept(ostream &out,CacheFile &Cache)
 	  I->CurrentVer == 0 || Cache[I].Delete() == true)
 	  I->CurrentVer == 0 || Cache[I].Delete() == true)
 	 continue;
 	 continue;
       
       
-      List += string(I.Name()) + " ";
+      List += I.FullName(true) + " ";
       VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n";
       VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n";
    }
    }
    ShowList(out,_("The following packages have been kept back:"),List,VersionsList);
    ShowList(out,_("The following packages have been kept back:"),List,VersionsList);
@@ -444,8 +448,10 @@ void ShowUpgraded(ostream &out,CacheFile &Cache)
       // Not interesting
       // Not interesting
       if (Cache[I].Upgrade() == false || Cache[I].NewInstall() == true)
       if (Cache[I].Upgrade() == false || Cache[I].NewInstall() == true)
 	 continue;
 	 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";
       VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n";
    }
    }
    ShowList(out,_("The following packages will be upgraded:"),List,VersionsList);
    ShowList(out,_("The following packages will be upgraded:"),List,VersionsList);
@@ -465,8 +471,10 @@ bool ShowDowngraded(ostream &out,CacheFile &Cache)
       // Not interesting
       // Not interesting
       if (Cache[I].Downgrade() == false || Cache[I].NewInstall() == true)
       if (Cache[I].Downgrade() == false || Cache[I].NewInstall() == true)
 	 continue;
 	 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";
       VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n";
    }
    }
    return ShowList(out,_("The following packages will be DOWNGRADED:"),List,VersionsList);
    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]);
       pkgCache::PkgIterator I(Cache,Cache.List[J]);
       if (Cache[I].InstallVer != (pkgCache::Version *)I.CurrentVer() &&
       if (Cache[I].InstallVer != (pkgCache::Version *)I.CurrentVer() &&
           I->SelectedState == pkgCache::State::Hold) {
           I->SelectedState == pkgCache::State::Hold) {
-         List += string(I.Name()) + " ";
+         List += I.FullName(true) + " ";
 		 VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n";
 		 VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n";
       }
       }
    }
    }
@@ -518,7 +526,7 @@ bool ShowEssential(ostream &out,CacheFile &Cache)
 	 if (Added[I->ID] == false)
 	 if (Added[I->ID] == false)
 	 {
 	 {
 	    Added[I->ID] = true;
 	    Added[I->ID] = true;
-	    List += string(I.Name()) + " ";
+	    List += I.FullName(true) + " ";
         //VersionsList += string(Cache[I].CurVersion) + "\n"; ???
         //VersionsList += string(Cache[I].CurVersion) + "\n"; ???
 	 }
 	 }
       }
       }
@@ -542,7 +550,7 @@ bool ShowEssential(ostream &out,CacheFile &Cache)
 	    Added[P->ID] = true;
 	    Added[P->ID] = true;
 	    
 	    
 	    char S[300];
 	    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;
 	    List += S;
         //VersionsList += "\n"; ???
         //VersionsList += "\n"; ???
 	 }	 
 	 }	 
@@ -566,6 +574,9 @@ void Stats(ostream &out,pkgDepCache &Dep)
    unsigned long ReInstall = 0;
    unsigned long ReInstall = 0;
    for (pkgCache::PkgIterator I = Dep.PkgBegin(); I.end() == false; I++)
    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)
       if (Dep[I].NewInstall() == true)
 	 Install++;
 	 Install++;
       else
       else
@@ -1084,7 +1095,7 @@ bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache,
       if (found_one == true)
       if (found_one == true)
       {
       {
 	 ioprintf(c1out,_("Note, selecting %s instead of %s\n"),
 	 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;
 	 Pkg = Prov;
       }
       }
    }
    }
@@ -1095,7 +1106,7 @@ bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache,
    {
    {
       if (AllowFail == true)
       if (AllowFail == true)
 	 ioprintf(c1out,_("Skipping %s, it is already installed and upgrade is not set.\n"),
 	 ioprintf(c1out,_("Skipping %s, it is already installed and upgrade is not set.\n"),
-		  Pkg.Name());
+		  Pkg.FullName(true).c_str());
       return true;
       return true;
    }
    }
 
 
@@ -1122,7 +1133,7 @@ bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache,
       if (AllowFail == false)
       if (AllowFail == false)
 	 return 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;
       return true;
    }
    }
    
    
@@ -1134,7 +1145,7 @@ bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache,
       if (Pkg->ProvidesList != 0)
       if (Pkg->ProvidesList != 0)
       {
       {
 	 ioprintf(c1out,_("Package %s is a virtual package provided by:\n"),
 	 ioprintf(c1out,_("Package %s is a virtual package provided by:\n"),
-		  Pkg.Name());
+		  Pkg.FullName(true).c_str());
 	 
 	 
 	 pkgCache::PrvIterator I = Pkg.ProvidesList();
 	 pkgCache::PrvIterator I = Pkg.ProvidesList();
 	 for (; I.end() == false; I++)
 	 for (; I.end() == false; I++)
@@ -1144,10 +1155,10 @@ bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache,
 	    if (Cache[Pkg].CandidateVerIter(Cache) == I.OwnerVer())
 	    if (Cache[Pkg].CandidateVerIter(Cache) == I.OwnerVer())
 	    {
 	    {
 	       if (Cache[Pkg].Install() == true && Cache[Pkg].NewInstall() == false)
 	       if (Cache[Pkg].Install() == true && Cache[Pkg].NewInstall() == false)
-		  c1out << "  " << Pkg.Name() << " " << I.OwnerVer().VerStr() <<
+		  c1out << "  " << Pkg.FullName(true) << " " << I.OwnerVer().VerStr() <<
 		  _(" [Installed]") << endl;
 		  _(" [Installed]") << endl;
 	       else
 	       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;
 	 c1out << _("You should explicitly select one to install.") << endl;
@@ -1157,7 +1168,7 @@ bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache,
 	 ioprintf(c1out,
 	 ioprintf(c1out,
 	 _("Package %s is not available, but is referred to by another package.\n"
 	 _("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"
 	   "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 List;
 	 string VersionsList;
 	 string VersionsList;
@@ -1171,13 +1182,13 @@ bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache,
 	    if (Seen[Dep.ParentPkg()->ID] == true)
 	    if (Seen[Dep.ParentPkg()->ID] == true)
 	       continue;
 	       continue;
 	    Seen[Dep.ParentPkg()->ID] = true;
 	    Seen[Dep.ParentPkg()->ID] = true;
-	    List += string(Dep.ParentPkg().Name()) + " ";
+	    List += Dep.ParentPkg().FullName(true) + " ";
         //VersionsList += string(Dep.ParentPkg().CurVersion) + "\n"; ???
         //VersionsList += string(Dep.ParentPkg().CurVersion) + "\n"; ???
 	 }	    
 	 }	    
 	 ShowList(c1out,_("However the following packages replace it:"),List,VersionsList);
 	 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;
       return false;
    }
    }
 
 
@@ -1198,7 +1209,7 @@ bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache,
       {
       {
 	 if (Pkg->CurrentVer == 0 || Pkg.CurrentVer().Downloadable() == false)
 	 if (Pkg->CurrentVer == 0 || Pkg.CurrentVer().Downloadable() == false)
 	    ioprintf(c1out,_("Reinstallation of %s is not possible, it cannot be downloaded.\n"),
 	    ioprintf(c1out,_("Reinstallation of %s is not possible, it cannot be downloaded.\n"),
-		     Pkg.Name());
+		     Pkg.FullName(true).c_str());
 	 else
 	 else
 	    Cache.SetReInstall(Pkg,true);
 	    Cache.SetReInstall(Pkg,true);
       }      
       }      
@@ -1206,7 +1217,7 @@ bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache,
       {
       {
 	 if (AllowFail == true)
 	 if (AllowFail == true)
 	    ioprintf(c1out,_("%s is already the newest version.\n"),
 	    ioprintf(c1out,_("%s is already the newest version.\n"),
-		     Pkg.Name());
+		     Pkg.FullName(true).c_str());
       }      
       }      
    }   
    }   
    else
    else
@@ -1235,15 +1246,15 @@ bool TryToChangeVer(pkgCache::PkgIterator Pkg,pkgDepCache &Cache,
    {
    {
       if (IsRel == true)
       if (IsRel == true)
 	 return _error->Error(_("Release '%s' for '%s' was not found"),
 	 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"),
       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)
    if (strcmp(VerTag,Ver.VerStr()) != 0)
    {
    {
       ioprintf(c1out,_("Selected version %s (%s) for %s\n"),
       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);
    Cache.SetCandidateVersion(Ver);
@@ -1499,7 +1510,7 @@ bool DoAutomaticRemove(CacheFile &Cache)
       {
       {
 	 if(Pkg.CurrentVer() != 0 || Cache[Pkg].Install())
 	 if(Pkg.CurrentVer() != 0 || Cache[Pkg].Install())
 	    if(Debug)
 	    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)
 	 if (doAutoRemove)
 	 {
 	 {
@@ -1518,7 +1529,7 @@ bool DoAutomaticRemove(CacheFile &Cache)
 	       // we don't need to fill the strings if we don't need them
 	       // we don't need to fill the strings if we don't need them
 	       if (smallList == false)
 	       if (smallList == false)
 	       {
 	       {
-		 autoremovelist += string(Pkg.Name()) + " ";
+		 autoremovelist += Pkg.FullName(true) + " ";
 		 autoremoveversions += string(Cache[Pkg].CandVersion) + "\n";
 		 autoremoveversions += string(Cache[Pkg].CandVersion) + "\n";
 	       }
 	       }
 	    }
 	    }
@@ -1793,7 +1804,7 @@ bool DoInstall(CommandLine &CmdL)
 	       _config->FindB("APT::Get::Download-Only",false) == false)
 	       _config->FindB("APT::Get::Download-Only",false) == false)
 	    {
 	    {
 	       ioprintf(c1out,_("%s set to manually installed.\n"),
 	       ioprintf(c1out,_("%s set to manually installed.\n"),
-			Pkg.Name());
+			Pkg.FullName(true).c_str());
 	       Cache->MarkAuto(Pkg,false);
 	       Cache->MarkAuto(Pkg,false);
 	       AutoMarkChanged++;
 	       AutoMarkChanged++;
 	    }
 	    }
@@ -1862,7 +1873,7 @@ bool DoInstall(CommandLine &CmdL)
 		break;
 		break;
 	 
 	 
 	 if (*J == 0) {
 	 if (*J == 0) {
-	    List += string(I.Name()) + " ";
+	    List += I.FullName(true) + " ";
 	    VersionsList += string(Cache[I].CandVersion) + "\n";
 	    VersionsList += string(Cache[I].CandVersion) + "\n";
 	 }
 	 }
       }
       }
@@ -1898,7 +1909,7 @@ bool DoInstall(CommandLine &CmdL)
 	    for(;;)
 	    for(;;)
 	    {
 	    {
 	       /* Skip if package is  installed already, or is about to be */
 	       /* 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
 	       if ((*Start.TargetPkg()).SelectedState == pkgCache::State::Install
 		   || Cache[Start.TargetPkg()].Install())
 		   || Cache[Start.TargetPkg()].Install())
@@ -2453,7 +2464,7 @@ bool DoBuildDep(CommandLine &CmdL)
             
             
       // Process the build-dependencies
       // Process the build-dependencies
       vector<pkgSrcRecords::Parser::BuildDepRec> BuildDeps;
       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());
       	return _error->Error(_("Unable to get build-dependency information for %s"),Src.c_str());
    
    
       // Also ensure that build-essential packages are present
       // Also ensure that build-essential packages are present
@@ -2552,7 +2563,7 @@ bool DoBuildDep(CommandLine &CmdL)
             for (; Prv.end() != true; Prv++)
             for (; Prv.end() != true; Prv++)
 	    {
 	    {
                if (_config->FindB("Debug::BuildDeps",false) == true)
                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)
 	       if ((*Cache)[Prv.OwnerPkg()].InstVerIter(*Cache).end() == false)
 	          break;
 	          break;
@@ -2593,7 +2604,7 @@ bool DoBuildDep(CommandLine &CmdL)
                if (Prv.end() == false)
                if (Prv.end() == false)
                {
                {
                   if (_config->FindB("Debug::BuildDeps",false) == true)
                   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;
                   skipAlternatives = hasAlternatives;
                   continue;
                   continue;
                }
                }
@@ -2618,7 +2629,7 @@ bool DoBuildDep(CommandLine &CmdL)
                   return _error->Error(_("Failed to satisfy %s dependency for %s: Installed package %s is too new"),
                   return _error->Error(_("Failed to satisfy %s dependency for %s: Installed package %s is too new"),
                                        Last->BuildDepType((*D).Type),
                                        Last->BuildDepType((*D).Type),
                                        Src.c_str(),
                                        Src.c_str(),
-                                       Pkg.Name());
+                                       Pkg.FullName(true).c_str());
                }
                }
             }
             }
 
 
@@ -2667,7 +2678,6 @@ bool DoBuildDep(CommandLine &CmdL)
    return true;
    return true;
 }
 }
 									/*}}}*/
 									/*}}}*/
-
 // DoMoo - Never Ask, Never Tell					/*{{{*/
 // DoMoo - Never Ask, Never Tell					/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* */
 /* */

+ 2 - 1
debian/apt-doc.docs

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

+ 6 - 7
debian/changelog

@@ -5,6 +5,12 @@ apt (0.7.26) UNRELEASED; urgency=low
   * Spanish manpages translation update. Closes: #573293
   * Spanish manpages translation update. Closes: #573293
 
 
   [ David Kalnischkies ]
   [ 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)
   * Switch to dpkg-source 3.0 (native) format
   * Switch to dpkg-source 3.0 (native) format
   * apt-pkg/depcache.cc:
   * apt-pkg/depcache.cc:
     - remove Auto-Installed information from extended_states
     - remove Auto-Installed information from extended_states
@@ -1449,13 +1455,6 @@ apt (0.7.6) unstable; urgency=low
 
 
  -- Otavio Salvador <otavio@debian.org>  Wed, 01 Aug 2007 19:49:51 -0300
  -- Otavio Salvador <otavio@debian.org>  Wed, 01 Aug 2007 19:49:51 -0300
 
 
-apt (0.7.6) unstable; urgency=low
-
-  * Applied patch from Aurelien Jarno <aurel32@debian.org> to fix wrong
-    directory downloading on non-linux architectures (closes: #435597)
-
- -- Otavio Salvador <otavio@debian.org>  Wed, 01 Aug 2007 19:49:51 -0300
-
 apt (0.7.5) unstable; urgency=low
 apt (0.7.5) unstable; urgency=low
 
 
   [ Otavio Salvador ]
   [ Otavio Salvador ]