]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/pkgcache.cc
Merge branch 'debian/sid' of ssh://git.debian.org/git/apt/apt into debian/sid
[apt.git] / apt-pkg / pkgcache.cc
index 4fbf42c4bb6c4f82dd919ad8fbe2647eb58df06d..67a2a709dbe4e1ef12cb66689f74112766063aba 100644 (file)
@@ -8,7 +8,7 @@
    Please see doc/apt-pkg/cache.sgml for a more detailed description of 
    this format. Also be sure to keep that file up-to-date!!
    
-   This is the general utility functions for cache managment. They provide
+   This is the general utility functions for cache management. They provide
    a complete set of accessor functions for the cache. The cacheiterators
    header contains the STL-like iterators that can be used to easially
    navigate the cache as well as seemlessly dereference the mmap'd 
    ##################################################################### */
                                                                        /*}}}*/
 // Include Files                                                       /*{{{*/
+#include<config.h>
+
 #include <apt-pkg/pkgcache.h>
-#include <apt-pkg/indexfile.h>
+#include <apt-pkg/policy.h>
 #include <apt-pkg/version.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/strutl.h>
 #include <apt-pkg/configuration.h>
+#include <apt-pkg/aptconfiguration.h>
+#include <apt-pkg/macros.h>
 
-#include <apti18n.h>
-    
 #include <string>
 #include <sys/stat.h>
 #include <unistd.h>
-
 #include <ctype.h>
-#include <system.h>
+
+#include <apti18n.h>
                                                                        /*}}}*/
 
 using std::string;
@@ -49,11 +51,12 @@ pkgCache::Header::Header()
    
    /* Whenever the structures change the major version should be bumped,
       whenever the generator changes the minor version should be bumped. */
-   MajorVersion = 7;
-   MinorVersion = 0;
+   MajorVersion = 8;
+   MinorVersion = 1;
    Dirty = false;
    
    HeaderSz = sizeof(pkgCache::Header);
+   GroupSz = sizeof(pkgCache::Group);
    PackageSz = sizeof(pkgCache::Package);
    PackageFileSz = sizeof(pkgCache::PackageFile);
    VersionSz = sizeof(pkgCache::Version);
@@ -63,6 +66,7 @@ pkgCache::Header::Header()
    VerFileSz = sizeof(pkgCache::VerFile);
    DescFileSz = sizeof(pkgCache::DescFile);
    
+   GroupCount = 0;
    PackageCount = 0;
    VersionCount = 0;
    DescriptionCount = 0;
@@ -78,8 +82,11 @@ pkgCache::Header::Header()
    StringList = 0;
    VerSysName = 0;
    Architecture = 0;
-   memset(HashTable,0,sizeof(HashTable));
+   memset(PkgHashTable,0,sizeof(PkgHashTable));
+   memset(GrpHashTable,0,sizeof(GrpHashTable));
    memset(Pools,0,sizeof(Pools));
+
+   CacheFileSize = 0;
 }
                                                                        /*}}}*/
 // Cache::Header::CheckSizes - Check if the two headers have same *sz  /*{{{*/
@@ -88,6 +95,7 @@ pkgCache::Header::Header()
 bool pkgCache::Header::CheckSizes(Header &Against) const
 {
    if (HeaderSz == Against.HeaderSz &&
+       GroupSz == Against.GroupSz &&
        PackageSz == Against.PackageSz &&
        PackageFileSz == Against.PackageFileSz &&
        VersionSz == Against.VersionSz &&
@@ -106,6 +114,10 @@ bool pkgCache::Header::CheckSizes(Header &Against) const
 /* */
 pkgCache::pkgCache(MMap *Map, bool DoMap) : Map(*Map)
 {
+   // call getArchitectures() with cached=false to ensure that the 
+   // architectures cache is re-evaulated. this is needed in cases
+   // when the APT::Architecture field changes between two cache creations
+   MultiArchEnabled = APT::Configuration::getArchitectures(false).size() > 1;
    if (DoMap == true)
       ReMap();
 }
@@ -113,10 +125,11 @@ pkgCache::pkgCache(MMap *Map, bool DoMap) : Map(*Map)
 // Cache::ReMap - Reopen the cache file                                        /*{{{*/
 // ---------------------------------------------------------------------
 /* If the file is already closed then this will open it open it. */
-bool pkgCache::ReMap()
+bool pkgCache::ReMap(bool const &Errorchecks)
 {
    // Apply the typecasts.
    HeaderP = (Header *)Map.Data();
+   GrpP = (Group *)Map.Data();
    PkgP = (Package *)Map.Data();
    VerFileP = (VerFile *)Map.Data();
    DescFileP = (DescFile *)Map.Data();
@@ -128,6 +141,9 @@ bool pkgCache::ReMap()
    StringItemP = (StringItem *)Map.Data();
    StrP = (char *)Map.Data();
 
+   if (Errorchecks == false)
+      return true;
+
    if (Map.Size() == 0 || HeaderP == 0)
       return _error->Error(_("Empty package cache"));
    
@@ -142,6 +158,9 @@ bool pkgCache::ReMap()
        HeaderP->CheckSizes(DefHeader) == false)
       return _error->Error(_("The package cache file is an incompatible version"));
 
+   if (Map.Size() < HeaderP->CacheFileSize)
+      return _error->Error(_("The package cache file is corrupted, it is too small"));
+
    // Locate our VS..
    if (HeaderP->VerSysName == 0 ||
        (VS = pkgVersioningSystem::GetVS(StrP + HeaderP->VerSysName)) == 0)
@@ -162,58 +181,129 @@ bool pkgCache::ReMap()
 unsigned long pkgCache::sHash(const string &Str) const
 {
    unsigned long Hash = 0;
-   for (string::const_iterator I = Str.begin(); I != Str.end(); I++)
-      Hash = 5*Hash + tolower(*I);
-   return Hash % _count(HeaderP->HashTable);
+   for (string::const_iterator I = Str.begin(); I != Str.end(); ++I)
+      Hash = 41 * Hash + tolower_ascii(*I);
+   return Hash % _count(HeaderP->PkgHashTable);
 }
 
 unsigned long pkgCache::sHash(const char *Str) const
 {
-   unsigned long Hash = 0;
-   for (const char *I = Str; *I != 0; I++)
-      Hash = 5*Hash + tolower(*I);
-   return Hash % _count(HeaderP->HashTable);
+   unsigned long Hash = tolower_ascii(*Str);
+   for (const char *I = Str + 1; *I != 0; ++I)
+      Hash = 41 * Hash + tolower_ascii(*I);
+   return Hash % _count(HeaderP->PkgHashTable);
 }
-
                                                                        /*}}}*/
-// Cache::FindPkg - Locate a package by name                           /*{{{*/
+// Cache::SingleArchFindPkg - Locate a package by name                 /*{{{*/
 // ---------------------------------------------------------------------
-/* Returns 0 on error, pointer to the package otherwise */
-pkgCache::PkgIterator pkgCache::FindPkg(const string &Name)
+/* Returns 0 on error, pointer to the package otherwise
+   The multiArch enabled methods will fallback to this one as it is (a bit)
+   faster for single arch environments and realworld is mostly singlearch… */
+pkgCache::PkgIterator pkgCache::SingleArchFindPkg(const string &Name)
 {
    // Look at the hash bucket
-   Package *Pkg = PkgP + HeaderP->HashTable[Hash(Name)];
+   Package *Pkg = PkgP + HeaderP->PkgHashTable[Hash(Name)];
    for (; Pkg != PkgP; Pkg = PkgP + Pkg->NextPackage)
    {
-      if (Pkg->Name != 0 && StrP[Pkg->Name] == Name[0] &&
-         stringcasecmp(Name,StrP + Pkg->Name) == 0)
-        return PkgIterator(*this,Pkg);
+      if (unlikely(Pkg->Name == 0))
+        continue;
+
+      int const cmp = strcasecmp(Name.c_str(), StrP + Pkg->Name);
+      if (cmp == 0)
+        return PkgIterator(*this, Pkg);
+      else if (cmp < 0)
+        break;
    }
    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) {
+       size_t const found = Name.find(':');
+       if (found == string::npos)
+       {
+               if (MultiArchCache() == false)
+                       return SingleArchFindPkg(Name);
+               else
+                       return FindPkg(Name, "native");
+       }
+       string const Arch = Name.substr(found+1);
+       /* Beware: This is specialcased to handle pkg:any in dependencies as
+          these are linked to virtual pkg:any named packages with all archs.
+          If you want any arch from a given pkg, use FindPkg(pkg,arch) */
+       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 && Arch != "none") {
+               if (Arch == "native" || Arch == "all" || Arch == "any" ||
+                   Arch == NativeArch())
+                       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 (unlikely(Grp->Name == 0))
+                  continue;
+
+               int const cmp = strcasecmp(Name.c_str(), StrP + Grp->Name);
+               if (cmp == 0)
+                       return GrpIterator(*this, Grp);
+               else if (cmp < 0)
+                       break;
+       }
+
+       return GrpIterator(*this,0);
+}
+                                                                       /*}}}*/
 // Cache::CompTypeDeb - Return a string describing the compare type    /*{{{*/
 // ---------------------------------------------------------------------
 /* This returns a string representation of the dependency compare 
    type in the weird debian style.. */
 const char *pkgCache::CompTypeDeb(unsigned char Comp)
 {
-   const char *Ops[] = {"","<=",">=","<<",">>","=","!="};
-   if ((unsigned)(Comp & 0xF) < 7)
-      return Ops[Comp & 0xF];
-   return "";   
+   const char * const Ops[] = {"","<=",">=","<<",">>","=","!="};
+   if (unlikely((unsigned)(Comp & 0xF) >= sizeof(Ops)/sizeof(Ops[0])))
+      return "";
+   return Ops[Comp & 0xF];
 }
                                                                        /*}}}*/
 // Cache::CompType - 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
    type */
 const char *pkgCache::CompType(unsigned char Comp)
 {
-   const char *Ops[] = {"","<=",">=","<",">","=","!="};
-   if ((unsigned)(Comp & 0xF) < 7)
-      return Ops[Comp & 0xF];
-   return "";   
+   const char * const Ops[] = {"","<=",">=","<",">","=","!="};
+   if (unlikely((unsigned)(Comp & 0xF) >= sizeof(Ops)/sizeof(Ops[0])))
+      return "";
+   return Ops[Comp & 0xF];
 }
                                                                        /*}}}*/
 // Cache::DepType - Return a string describing the dep type            /*{{{*/
@@ -223,7 +313,7 @@ const char *pkgCache::DepType(unsigned char Type)
 {
    const char *Types[] = {"",_("Depends"),_("PreDepends"),_("Suggests"),
                           _("Recommends"),_("Conflicts"),_("Replaces"),
-                          _("Obsoletes"),_("Breaks")};
+                          _("Obsoletes"),_("Breaks"), _("Enhances")};
    if (Type < sizeof(Types)/sizeof(*Types))
       return Types[Type];
    return "";
@@ -241,11 +331,102 @@ const char *pkgCache::Priority(unsigned char Prio)
    return 0;
 }
                                                                        /*}}}*/
-// Bases for iterator classes                                          /*{{{*/
-void pkgCache::VerIterator::_dummy() {}
-void pkgCache::DepIterator::_dummy() {}
-void pkgCache::PrvIterator::_dummy() {}
-void pkgCache::DescIterator::_dummy() {}
+// GrpIterator::FindPkg - Locate a package by arch                     /*{{{*/
+// ---------------------------------------------------------------------
+/* Returns an End-Pointer on error, pointer to the package otherwise */
+pkgCache::PkgIterator pkgCache::GrpIterator::FindPkg(string Arch) const {
+       if (unlikely(IsGood() == false || S->FirstPackage == 0))
+               return PkgIterator(*Owner, 0);
+
+       /* 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);
+
+       char const* const myArch = Owner->NativeArch();
+       /* 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 == "all") {
+               pkgCache::Package *Pkg = Owner->PkgP + S->LastPackage;
+               if (strcasecmp(myArch, Owner->StrP + Pkg->Arch) == 0)
+                       return PkgIterator(*Owner, Pkg);
+               Arch = myArch;
+       }
+
+       /* Iterate over the list to find the matching arch
+          unfortunately this list includes "package noise"
+          (= different packages with same calculated hash),
+          so we need to check the name also */
+       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::FindPreferredPkg - Locate the "best" package           /*{{{*/
+// ---------------------------------------------------------------------
+/* Returns an End-Pointer on error, pointer to the package otherwise */
+pkgCache::PkgIterator pkgCache::GrpIterator::FindPreferredPkg(bool const &PreferNonVirtual) const {
+       pkgCache::PkgIterator Pkg = FindPkg("native");
+       if (Pkg.end() == false && (PreferNonVirtual == false || Pkg->VersionList != 0))
+               return Pkg;
+
+       std::vector<std::string> const archs = APT::Configuration::getArchitectures();
+       for (std::vector<std::string>::const_iterator a = archs.begin();
+            a != archs.end(); ++a) {
+               Pkg = FindPkg(*a);
+               if (Pkg.end() == false && (PreferNonVirtual == false || Pkg->VersionList != 0))
+                       return Pkg;
+       }
+       // packages without an architecture
+       Pkg = FindPkg("none");
+       if (Pkg.end() == false && (PreferNonVirtual == false || Pkg->VersionList != 0))
+               return Pkg;
+
+       if (PreferNonVirtual == true)
+               return FindPreferredPkg(false);
+       return PkgIterator(*Owner, 0);
+}
+                                                                       /*}}}*/
+// GrpIterator::NextPkg - Locate the next package in the group         /*{{{*/
+// ---------------------------------------------------------------------
+/* Returns an End-Pointer on error, pointer to the package otherwise.
+   We can't simply ++ to the next as the next package of the last will
+   be from a different group (with the same hash value) */
+pkgCache::PkgIterator pkgCache::GrpIterator::NextPkg(pkgCache::PkgIterator const &LastPkg) const {
+       if (unlikely(IsGood() == false || S->FirstPackage == 0 ||
+           LastPkg.end() == true))
+               return PkgIterator(*Owner, 0);
+
+       if (S->LastPackage == LastPkg.Index())
+               return PkgIterator(*Owner, 0);
+
+       return PkgIterator(*Owner, Owner->PkgP + LastPkg->NextPackage);
+}
+                                                                       /*}}}*/
+// GrpIterator::operator ++ - Postfix incr                             /*{{{*/
+// ---------------------------------------------------------------------
+/* This will advance to the next logical group in the hash table. */
+void pkgCache::GrpIterator::operator ++(int) 
+{
+   // Follow the current links
+   if (S != Owner->GrpP)
+      S = Owner->GrpP + S->Next;
+
+   // Follow the hash table
+   while (S == Owner->GrpP && (HashIndex+1) < (signed)_count(Owner->HeaderP->GrpHashTable))
+   {
+      HashIndex++;
+      S = Owner->GrpP + Owner->HeaderP->GrpHashTable[HashIndex];
+   }
+};
                                                                        /*}}}*/
 // PkgIterator::operator ++ - Postfix incr                             /*{{{*/
 // ---------------------------------------------------------------------
@@ -253,14 +434,14 @@ void pkgCache::DescIterator::_dummy() {}
 void pkgCache::PkgIterator::operator ++(int) 
 {
    // Follow the current links
-   if (Pkg != Owner->PkgP)
-      Pkg = Owner->PkgP + Pkg->NextPackage;
+   if (S != Owner->PkgP)
+      S = Owner->PkgP + S->NextPackage;
 
    // Follow the hash table
-   while (Pkg == Owner->PkgP && (HashIndex+1) < (signed)_count(Owner->HeaderP->HashTable))
+   while (S == Owner->PkgP && (HashIndex+1) < (signed)_count(Owner->HeaderP->PkgHashTable))
    {
       HashIndex++;
-      Pkg = Owner->PkgP + Owner->HeaderP->HashTable[HashIndex];
+      S = Owner->PkgP + Owner->HeaderP->PkgHashTable[HashIndex];
    }
 };
                                                                        /*}}}*/
@@ -269,42 +450,114 @@ void pkgCache::PkgIterator::operator ++(int)
 /* By this we mean if it is either cleanly installed or cleanly removed. */
 pkgCache::PkgIterator::OkState pkgCache::PkgIterator::State() const
 {  
-   if (Pkg->InstState == pkgCache::State::ReInstReq ||
-       Pkg->InstState == pkgCache::State::HoldReInstReq)
+   if (S->InstState == pkgCache::State::ReInstReq ||
+       S->InstState == pkgCache::State::HoldReInstReq)
       return NeedsUnpack;
    
-   if (Pkg->CurrentState == pkgCache::State::UnPacked ||
-       Pkg->CurrentState == pkgCache::State::HalfConfigured ||
-      //we don't need to care for triggers awaiting packages
-      //dpkg will deal with them automatically when the 
-      //trigger pending action is run (those packages are usually
-      //in half-configured or triggers-pending state)
+   if (S->CurrentState == pkgCache::State::UnPacked ||
+       S->CurrentState == pkgCache::State::HalfConfigured)
+      // we leave triggers alone complettely. dpkg deals with
+      // them in a hard-to-predict manner and if they get 
+      // resolved by dpkg before apt run dpkg --configure on 
+      // the TriggersPending package dpkg returns a error
       //Pkg->CurrentState == pkgCache::State::TriggersAwaited
-       Pkg->CurrentState == pkgCache::State::TriggersPending)
+      //Pkg->CurrentState == pkgCache::State::TriggersPending)
       return NeedsConfigure;
    
-   if (Pkg->CurrentState == pkgCache::State::HalfInstalled ||
-       Pkg->InstState != pkgCache::State::Ok)
+   if (S->CurrentState == pkgCache::State::HalfInstalled ||
+       S->InstState != pkgCache::State::Ok)
       return NeedsUnpack;
       
    return NeedsNothing;
 }
                                                                        /*}}}*/
+// PkgIterator::CandVersion - Returns the candidate version string     /*{{{*/
+// ---------------------------------------------------------------------
+/* Return string representing of the candidate version. */
+const char *
+pkgCache::PkgIterator::CandVersion() const 
+{
+  //TargetVer is empty, so don't use it.
+  VerIterator version = pkgPolicy(Owner).GetCandidateVer(*this);
+  if (version.IsGood())
+    return version.VerStr();
+  return 0;
+};
+                                                                       /*}}}*/
+// PkgIterator::CurVersion - Returns the current version string                /*{{{*/
+// ---------------------------------------------------------------------
+/* Return string representing of the current version. */
+const char *
+pkgCache::PkgIterator::CurVersion() const 
+{
+  VerIterator version = CurrentVer();
+  if (version.IsGood())
+    return CurrentVer().VerStr();
+  return 0;
+};
+                                                                       /*}}}*/
+// ostream operator to handle string representation of a package       /*{{{*/
+// ---------------------------------------------------------------------
+/* Output name < cur.rent.version -> candid.ate.version | new.est.version > (section)
+   Note that the characters <|>() are all literal above. Versions will be omitted
+   if they provide no new information (e.g. there is no newer version than candidate)
+   If no version and/or section can be found "none" is used. */
+std::ostream& 
+operator<<(std::ostream& out, pkgCache::PkgIterator Pkg) 
+{
+   if (Pkg.end() == true)
+      return out << "invalid package";
+
+   string current = string(Pkg.CurVersion() == 0 ? "none" : Pkg.CurVersion());
+   string candidate = string(Pkg.CandVersion() == 0 ? "none" : Pkg.CandVersion());
+   string newest = string(Pkg.VersionList().end() ? "none" : Pkg.VersionList().VerStr());
+
+   out << Pkg.Name() << " [ " << Pkg.Arch() << " ] < " << current;
+   if (current != candidate)
+      out << " -> " << candidate;
+   if ( newest != "none" && candidate != newest)
+      out << " | " << newest;
+   out << " > ( " << string(Pkg.Section()==0?"none":Pkg.Section()) << " )";
+   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 &&
+       strcmp(Owner->NativeArch(), Arch()) != 0))
+      return fullname.append(":").append(Arch());
+   return fullname;
+}
+                                                                       /*}}}*/
 // DepIterator::IsCritical - Returns true if the dep is important      /*{{{*/
 // ---------------------------------------------------------------------
 /* Currently critical deps are defined as depends, predepends and
    conflicts (including dpkg's Breaks fields). */
-bool pkgCache::DepIterator::IsCritical()
+bool pkgCache::DepIterator::IsCritical() const
 {
-   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 (IsNegative() == true ||
+       S->Type == pkgCache::Dep::Depends ||
+       S->Type == pkgCache::Dep::PreDepends)
       return true;
    return false;
 }
                                                                        /*}}}*/
+// DepIterator::IsNegative - Returns true if the dep is a negative one /*{{{*/
+// ---------------------------------------------------------------------
+/* Some dependencies are positive like Depends and Recommends, others
+   are negative like Conflicts which can and should be handled differently */
+bool pkgCache::DepIterator::IsNegative() const
+{
+   return S->Type == Dep::DpkgBreaks ||
+         S->Type == Dep::Conflicts ||
+         S->Type == Dep::Obsoletes;
+}
+                                                                       /*}}}*/
 // DepIterator::SmartTargetPkg - Resolve dep target pointers w/provides        /*{{{*/
 // ---------------------------------------------------------------------
 /* This intellegently looks at dep target packages and tries to figure
@@ -318,7 +571,7 @@ bool pkgCache::DepIterator::IsCritical()
    In Conjunction with the DepCache the value of Result may not be 
    super-good since the policy may have made it uninstallable. Using
    AllTargets is better in this case. */
-bool pkgCache::DepIterator::SmartTargetPkg(PkgIterator &Result)
+bool pkgCache::DepIterator::SmartTargetPkg(PkgIterator &Result) const
 {
    Result = TargetPkg();
    
@@ -335,7 +588,7 @@ bool pkgCache::DepIterator::SmartTargetPkg(PkgIterator &Result)
       virtual package libc-dev which is provided by libc5-dev and libc6-dev
       we must ignore libc5-dev when considering the provides list. */ 
    PrvIterator PStart = Result.ProvidesList();
-   for (; PStart.end() != true && PStart.OwnerPkg() == ParentPkg(); PStart++);
+   for (; PStart.end() != true && PStart.OwnerPkg() == ParentPkg(); ++PStart);
 
    // Nothing but indirect self provides
    if (PStart.end() == true)
@@ -343,7 +596,7 @@ bool pkgCache::DepIterator::SmartTargetPkg(PkgIterator &Result)
    
    // Check for single packages in the provides list
    PrvIterator P = PStart;
-   for (; P.end() != true; P++)
+   for (; P.end() != true; ++P)
    {
       // Skip over self provides
       if (P.OwnerPkg() == ParentPkg())
@@ -367,7 +620,7 @@ bool pkgCache::DepIterator::SmartTargetPkg(PkgIterator &Result)
    provides. It includes every possible package-version that could satisfy
    the dependency. The last item in the list has a 0. The resulting pointer
    must be delete [] 'd */
-pkgCache::Version **pkgCache::DepIterator::AllTargets()
+pkgCache::Version **pkgCache::DepIterator::AllTargets() const
 {
    Version **Res = 0;
    unsigned long Size =0;
@@ -377,34 +630,26 @@ pkgCache::Version **pkgCache::DepIterator::AllTargets()
       PkgIterator DPkg = TargetPkg();
 
       // 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 (IsIgnorable(I.ParentPkg()) == true)
            continue;
-
-        if ((Dep->Type == pkgCache::Dep::Conflicts ||
-             Dep->Type == pkgCache::Dep::DpkgBreaks ||
-             Dep->Type == pkgCache::Dep::Obsoletes) &&
-            ParentPkg() == I.ParentPkg())
+        if (IsSatisfied(I) == false)
            continue;
-        
+
         Size++;
         if (Res != 0)
            *End++ = I;
       }
       
       // 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 (IsIgnorable(I) == true)
            continue;
-        
-        if ((Dep->Type == pkgCache::Dep::Conflicts ||
-             Dep->Type == pkgCache::Dep::DpkgBreaks ||
-             Dep->Type == pkgCache::Dep::Obsoletes) &&
-            ParentPkg() == I.OwnerPkg())
+        if (IsSatisfied(I) == false)
            continue;
-        
+
         Size++;
         if (Res != 0)
            *End++ = I.OwnerVer();
@@ -439,13 +684,111 @@ void pkgCache::DepIterator::GlobOr(DepIterator &Start,DepIterator &End)
    End = *this;
    for (bool LastOR = true; end() == false && LastOR == true;)
    {
-      LastOR = (Dep->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or;
+      LastOR = (S->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or;
       (*this)++;
       if (LastOR == true)
         End = (*this);
    }
 }
                                                                        /*}}}*/
+// DepIterator::IsIgnorable - should this packag/providr be ignored?   /*{{{*/
+// ---------------------------------------------------------------------
+/* Deps like self-conflicts should be ignored as well as implicit conflicts
+   on virtual packages. */
+bool pkgCache::DepIterator::IsIgnorable(PkgIterator const &Pkg) const
+{
+   if (IsNegative() == false)
+      return false;
+
+   pkgCache::PkgIterator PP = ParentPkg();
+   pkgCache::PkgIterator PT = TargetPkg();
+   if (PP->Group != PT->Group)
+      return false;
+   // self-conflict
+   if (PP == PT)
+      return true;
+   pkgCache::VerIterator PV = ParentVer();
+   // ignore group-conflict on a M-A:same package - but not our implicit dependencies
+   // so that we can have M-A:same packages conflicting with their own real name
+   if ((PV->MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same)
+   {
+      // Replaces: ${self}:other ( << ${binary:Version})
+      if (S->Type == pkgCache::Dep::Replaces && S->CompareOp == pkgCache::Dep::Less && strcmp(PV.VerStr(), TargetVer()) == 0)
+        return false;
+      // Breaks: ${self}:other (!= ${binary:Version})
+      if (S->Type == pkgCache::Dep::DpkgBreaks && S->CompareOp == pkgCache::Dep::NotEquals && strcmp(PV.VerStr(), TargetVer()) == 0)
+        return false;
+      return true;
+   }
+
+   return false;
+}
+bool pkgCache::DepIterator::IsIgnorable(PrvIterator const &Prv) const
+{
+   if (IsNegative() == false)
+      return false;
+
+   PkgIterator const Pkg = ParentPkg();
+   /* Provides may never be applied against the same package (or group)
+      if it is a conflicts. See the comment above. */
+   if (Prv.OwnerPkg()->Group == Pkg->Group)
+      return true;
+   // Implicit group-conflicts should not be applied on providers of other groups
+   if (Pkg->Group == TargetPkg()->Group && Prv.OwnerPkg()->Group != Pkg->Group)
+      return true;
+
+   return false;
+}
+                                                                       /*}}}*/
+// DepIterator::IsMultiArchImplicit - added by the cache generation    /*{{{*/
+// ---------------------------------------------------------------------
+/* MultiArch can be translated to SingleArch for an resolver and we did so,
+   by adding dependencies to help the resolver understand the problem, but
+   sometimes it is needed to identify these to ignore them… */
+bool pkgCache::DepIterator::IsMultiArchImplicit() const
+{
+   if (ParentPkg()->Arch != TargetPkg()->Arch &&
+       (S->Type == pkgCache::Dep::Replaces ||
+       S->Type == pkgCache::Dep::DpkgBreaks ||
+       S->Type == pkgCache::Dep::Conflicts))
+      return true;
+   return false;
+}
+                                                                       /*}}}*/
+// DepIterator::IsSatisfied - check if a version satisfied the dependency /*{{{*/
+bool pkgCache::DepIterator::IsSatisfied(VerIterator const &Ver) const
+{
+   return Owner->VS->CheckDep(Ver.VerStr(),S->CompareOp,TargetVer());
+}
+bool pkgCache::DepIterator::IsSatisfied(PrvIterator const &Prv) const
+{
+   return Owner->VS->CheckDep(Prv.ProvideVersion(),S->CompareOp,TargetVer());
+}
+                                                                       /*}}}*/
+// ostream operator to handle string representation of a dependecy     /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+std::ostream& operator<<(std::ostream& out, pkgCache::DepIterator D)
+{
+   if (D.end() == true)
+      return out << "invalid dependency";
+
+   pkgCache::PkgIterator P = D.ParentPkg();
+   pkgCache::PkgIterator T = D.TargetPkg();
+
+   out << (P.end() ? "invalid pkg" : P.FullName(false)) << " " << D.DepType()
+       << " on ";
+   if (T.end() == true)
+      out << "invalid pkg";
+   else
+      out << T;
+
+   if (D->Version != 0)
+      out << " (" << D.CompType() << " " << D.TargetVer() << ")";
+
+   return out;
+}
+                                                                       /*}}}*/
 // VerIterator::CompareVer - Fast version compare for same pkgs                /*{{{*/
 // ---------------------------------------------------------------------
 /* This just looks over the version list to see if B is listed before A. In
@@ -463,7 +806,7 @@ int pkgCache::VerIterator::CompareVer(const VerIterator &B) const
    /* Start at A and look for B. If B is found then A > B otherwise
       B was before A so A < B */
    VerIterator I = *this;
-   for (;I.end() == false; I++)
+   for (;I.end() == false; ++I)
       if (I == B)
         return 1;
    return -1;
@@ -475,7 +818,7 @@ int pkgCache::VerIterator::CompareVer(const VerIterator &B) const
 bool pkgCache::VerIterator::Downloadable() const
 {
    VerFileIterator Files = FileList();
-   for (; Files.end() == false; Files++)
+   for (; Files.end() == false; ++Files)
       if ((Files.File()->Flags & pkgCache::Flag::NotSource) != pkgCache::Flag::NotSource)
         return true;
    return false;
@@ -488,7 +831,8 @@ bool pkgCache::VerIterator::Downloadable() const
 bool pkgCache::VerIterator::Automatic() const
 {
    VerFileIterator Files = FileList();
-   for (; Files.end() == false; Files++)
+   for (; Files.end() == false; ++Files)
+      // Do not check ButAutomaticUpgrades here as it is kind of automatic…
       if ((Files.File()->Flags & pkgCache::Flag::NotAutomatic) != pkgCache::Flag::NotAutomatic)
         return true;
    return false;
@@ -502,7 +846,7 @@ pkgCache::VerFileIterator pkgCache::VerIterator::NewestFile() const
 {
    VerFileIterator Files = FileList();
    VerFileIterator Highest = Files;
-   for (; Files.end() == false; Files++)
+   for (; Files.end() == false; ++Files)
    {
       if (Owner->VS->CmpReleaseVer(Files.File().Version(),Highest.File().Version()) > 0)
         Highest = Files;
@@ -515,11 +859,11 @@ pkgCache::VerFileIterator pkgCache::VerIterator::NewestFile() const
 // ---------------------------------------------------------------------
 /* This describes the version from a release-centric manner. The output is a 
    list of Label:Version/Archive */
-string pkgCache::VerIterator::RelStr()
+string pkgCache::VerIterator::RelStr() const
 {
    bool First = true;
    string Res;
-   for (pkgCache::VerFileIterator I = this->FileList(); I.end() == false; I++)
+   for (pkgCache::VerFileIterator I = this->FileList(); I.end() == false; ++I)
    {
       // Do not print 'not source' entries'
       pkgCache::PkgFileIterator File = I.File();
@@ -528,7 +872,7 @@ string pkgCache::VerIterator::RelStr()
 
       // See if we have already printed this out..
       bool Seen = false;
-      for (pkgCache::VerFileIterator J = this->FileList(); I != J; J++)
+      for (pkgCache::VerFileIterator J = this->FileList(); I != J; ++J)
       {
         pkgCache::PkgFileIterator File2 = J.File();
         if (File2->Label == 0 || File->Label == 0)
@@ -574,10 +918,24 @@ string pkgCache::VerIterator::RelStr()
         else
            Res += File.Site();
       }      
-   }   
+   }
+   if (S->ParentPkg != 0)
+      Res.append(" [").append(Arch()).append("]");
    return Res;
 }
                                                                        /*}}}*/
+// VerIterator::MultiArchType - string representing MultiArch flag     /*{{{*/
+const char * pkgCache::VerIterator::MultiArchType() const
+{
+   if ((S->MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same)
+      return "same";
+   else if ((S->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign)
+      return "foreign";
+   else if ((S->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed)
+      return "allowed";
+   return "none";
+}
+                                                                       /*}}}*/
 // PkgFileIterator::IsOk - Checks if the cache is in sync with the file        /*{{{*/
 // ---------------------------------------------------------------------
 /* This stats the file and compares its stats with the ones that were
@@ -589,7 +947,7 @@ bool pkgCache::PkgFileIterator::IsOk()
    if (stat(FileName(),&Buf) != 0)
       return false;
 
-   if (Buf.st_size != (signed)File->Size || Buf.st_mtime != File->mtime)
+   if (Buf.st_size != (signed)S->Size || Buf.st_mtime != S->mtime)
       return false;
 
    return true;
@@ -607,10 +965,14 @@ string pkgCache::PkgFileIterator::RelStr()
       Res = Res + (Res.empty() == true?"o=":",o=")  + Origin();
    if (Archive() != 0)
       Res = Res + (Res.empty() == true?"a=":",a=")  + Archive();
+   if (Codename() != 0)
+      Res = Res + (Res.empty() == true?"n=":",n=")  + Codename();
    if (Label() != 0)
       Res = Res + (Res.empty() == true?"l=":",l=")  + Label();
    if (Component() != 0)
       Res = Res + (Res.empty() == true?"c=":",c=")  + Component();
+   if (Architecture() != 0)
+      Res = Res + (Res.empty() == true?"b=":",b=")  + Architecture();
    return Res;
 }
                                                                        /*}}}*/
@@ -621,14 +983,49 @@ string pkgCache::PkgFileIterator::RelStr()
  */
 pkgCache::DescIterator pkgCache::VerIterator::TranslatedDescription() const
 {
-   pkgCache::DescIterator DescDefault = DescriptionList();
-   pkgCache::DescIterator Desc = DescDefault;
-   for (; Desc.end() == false; Desc++)
-      if (pkgIndexFile::LanguageCode() == Desc.LanguageCode())
-        break;
-   if (Desc.end() == true) 
-      Desc = DescDefault;
-   return Desc;
+   std::vector<string> const lang = APT::Configuration::getLanguages();
+   for (std::vector<string>::const_iterator l = lang.begin();
+       l != lang.end(); ++l)
+   {
+      pkgCache::DescIterator Desc = DescriptionList();
+      for (; Desc.end() == false; ++Desc)
+        if (*l == Desc.LanguageCode())
+           break;
+      if (Desc.end() == true)
+      {
+        if (*l == "en")
+        {
+           Desc = DescriptionList();
+           for (; Desc.end() == false; ++Desc)
+              if (strcmp(Desc.LanguageCode(), "") == 0)
+                 break;
+           if (Desc.end() == true)
+              continue;
+        }
+        else
+           continue;
+      }
+      return Desc;
+   }
+   for (pkgCache::DescIterator Desc = DescriptionList();
+       Desc.end() == false; ++Desc)
+      if (strcmp(Desc.LanguageCode(), "") == 0)
+        return Desc;
+   return DescriptionList();
 };
 
                                                                        /*}}}*/
+// PrvIterator::IsMultiArchImplicit - added by the cache generation    /*{{{*/
+// ---------------------------------------------------------------------
+/* MultiArch can be translated to SingleArch for an resolver and we did so,
+   by adding provides to help the resolver understand the problem, but
+   sometimes it is needed to identify these to ignore them… */
+bool pkgCache::PrvIterator::IsMultiArchImplicit() const
+{
+   pkgCache::PkgIterator const Owner = OwnerPkg();
+   pkgCache::PkgIterator const Parent = ParentPkg();
+   if (strcmp(Owner.Arch(), Parent.Arch()) != 0 || Owner->Name == Parent->Name)
+      return true;
+   return false;
+}
+                                                                       /*}}}*/