]> git.saurik.com Git - apt.git/blobdiff - apt-private/private-output.cc
ensure FileFd doesn't try to open /dev/null as atomic and co
[apt.git] / apt-private / private-output.cc
index 158bd5c71a37fa22eb118d7d96f4395e94250771..b8e6dec029b30287b485497d5c1cf7b2c0a0ffe0 100644 (file)
@@ -25,6 +25,8 @@
 #include <signal.h>
 #include <sys/ioctl.h>
 
 #include <signal.h>
 #include <sys/ioctl.h>
 
+#include <sstream>
+
 #include <apti18n.h>
                                                                        /*}}}*/
 
 #include <apti18n.h>
                                                                        /*}}}*/
 
@@ -52,14 +54,14 @@ static void SigWinch(int)
 #endif
 }
                                                                        /*}}}*/
 #endif
 }
                                                                        /*}}}*/
-bool InitOutput()                                                      /*{{{*/
+bool InitOutput(std::basic_streambuf<char> * const out)                        /*{{{*/
 {
    if (!isatty(STDOUT_FILENO) && _config->FindI("quiet", -1) == -1)
       _config->Set("quiet","1");
 
 {
    if (!isatty(STDOUT_FILENO) && _config->FindI("quiet", -1) == -1)
       _config->Set("quiet","1");
 
-   c0out.rdbuf(cout.rdbuf());
-   c1out.rdbuf(cout.rdbuf());
-   c2out.rdbuf(cout.rdbuf());
+   c0out.rdbuf(out);
+   c1out.rdbuf(out);
+   c2out.rdbuf(out);
    if (_config->FindI("quiet",0) > 0)
       c0out.rdbuf(devnull.rdbuf());
    if (_config->FindI("quiet",0) > 1)
    if (_config->FindI("quiet",0) > 0)
       c0out.rdbuf(devnull.rdbuf());
    if (_config->FindI("quiet",0) > 1)
@@ -118,7 +120,7 @@ static std::string GetFlagsStr(pkgCacheFile &CacheFile, pkgCache::PkgIterator P)
    std::string flags_str;
    if (state.NowBroken())
       flags_str = "B";
    std::string flags_str;
    if (state.NowBroken())
       flags_str = "B";
-   if (P.CurrentVer() && state.Upgradable())
+   if (P.CurrentVer() && state.Upgradable() && state.CandidateVer != NULL)
       flags_str = "g";
    else if (P.CurrentVer() != NULL)
       flags_str = "i";
       flags_str = "g";
    else if (P.CurrentVer() != NULL)
       flags_str = "i";
@@ -164,15 +166,26 @@ static std::string GetVersion(pkgCacheFile &/*CacheFile*/, pkgCache::VerIterator
                                                                        /*}}}*/
 static std::string GetArchitecture(pkgCacheFile &CacheFile, pkgCache::PkgIterator P)/*{{{*/
 {
                                                                        /*}}}*/
 static std::string GetArchitecture(pkgCacheFile &CacheFile, pkgCache::PkgIterator P)/*{{{*/
 {
-   pkgPolicy *policy = CacheFile.GetPolicy();
-   pkgCache::VerIterator inst = P.CurrentVer();
-   pkgCache::VerIterator cand = policy->GetCandidateVer(P);
-
-   // this may happen for packages in dpkg "deinstall ok config-file" state
-   if (inst.IsGood() == false && cand.IsGood() == false)
-      return P.VersionList().Arch();
-
-   return inst ? inst.Arch() : cand.Arch();
+   if (P->CurrentVer == 0)
+   {
+      pkgDepCache * const DepCache = CacheFile.GetDepCache();
+      pkgDepCache::StateCache const &state = (*DepCache)[P];
+      if (state.CandidateVer != NULL)
+      {
+        pkgCache::VerIterator const CandV(CacheFile, state.CandidateVer);
+        return CandV.Arch();
+      }
+      else
+      {
+        pkgCache::VerIterator const V = P.VersionList();
+        if (V.end() == false)
+           return V.Arch();
+        else
+           return P.Arch();
+      }
+   }
+   else
+      return P.CurrentVer().Arch();
 }
                                                                        /*}}}*/
 static std::string GetShortDescription(pkgCacheFile &CacheFile, pkgRecords &records, pkgCache::PkgIterator P)/*{{{*/
 }
                                                                        /*}}}*/
 static std::string GetShortDescription(pkgCacheFile &CacheFile, pkgRecords &records, pkgCache::PkgIterator P)/*{{{*/
@@ -188,148 +201,103 @@ static std::string GetShortDescription(pkgCacheFile &CacheFile, pkgRecords &reco
    std::string ShortDescription = "(none)";
    if(ver)
    {
    std::string ShortDescription = "(none)";
    if(ver)
    {
-      pkgCache::DescIterator Desc = ver.TranslatedDescription();
-      pkgRecords::Parser & parser = records.Lookup(Desc.FileList());
-
-      ShortDescription = parser.ShortDesc();
+      pkgCache::DescIterator const Desc = ver.TranslatedDescription();
+      if (Desc.end() == false)
+      {
+        pkgRecords::Parser & parser = records.Lookup(Desc.FileList());
+        ShortDescription = parser.ShortDesc();
+      }
    }
    return ShortDescription;
 }
                                                                        /*}}}*/
    }
    return ShortDescription;
 }
                                                                        /*}}}*/
-void ListSingleVersion(pkgCacheFile &CacheFile, pkgRecords &records,   /*{{{*/
-                       pkgCache::VerIterator V, std::ostream &out,
-                       bool include_summary)
+static std::string GetLongDescription(pkgCacheFile &CacheFile, pkgRecords &records, pkgCache::PkgIterator P)/*{{{*/
 {
 {
-   pkgCache::PkgIterator P = V.ParentPkg();
+   pkgPolicy *policy = CacheFile.GetPolicy();
 
 
-   pkgDepCache *DepCache = CacheFile.GetDepCache();
-   pkgDepCache::StateCache &state = (*DepCache)[P];
+   pkgCache::VerIterator ver;
+   if (P->CurrentVer != 0)
+      ver = P.CurrentVer();
+   else
+      ver = policy->GetCandidateVer(P);
 
 
-   std::string suite = GetArchiveSuite(CacheFile, V);
-   std::string name_str = P.Name();
+   std::string const EmptyDescription = "(none)";
+   if(ver.end() == true)
+      return EmptyDescription;
 
 
-   if (_config->FindB("APT::Cmd::use-format", false))
+   pkgCache::DescIterator const Desc = ver.TranslatedDescription();
+   if (Desc.end() == false)
    {
    {
-      std::string format = _config->Find("APT::Cmd::format", "${db::Status-Abbrev} ${Package} ${Version} ${Origin} ${Description}");
-      std::string output = format;
-   
-      output = SubstVar(output, "${db::Status-Abbrev}", GetFlagsStr(CacheFile, P));
-      output = SubstVar(output, "${Package}", name_str);
-      output = SubstVar(output, "${installed:Version}", GetInstalledVersion(CacheFile, P));
-      output = SubstVar(output, "${candidate:Version}", GetCandidateVersion(CacheFile, P));
-      output = SubstVar(output, "${Version}", GetVersion(CacheFile, V));
-      output = SubstVar(output, "${Description}", GetShortDescription(CacheFile, records, P));
-      output = SubstVar(output, "${Origin}", GetArchiveSuite(CacheFile, V));
-      out << output << std::endl;
-   } else {
-      // raring/linux-kernel version [upradable: new-version]
-      //    description
-      pkgPolicy *policy = CacheFile.GetPolicy();
-      std::string VersionStr = GetVersion(CacheFile, V);
-      std::string CandidateVerStr = GetCandidateVersion(CacheFile, P);
-      std::string InstalledVerStr = GetInstalledVersion(CacheFile, P);
-      std::string StatusStr;
-      if(P.CurrentVer() == V && state.Upgradable()) {
-         strprintf(StatusStr, _("[installed,upgradable to: %s]"),
-                   CandidateVerStr.c_str());
-      } else if (P.CurrentVer() == V) {
-         if(!V.Downloadable())
-            StatusStr = _("[installed,local]");
-         else
-            if(V.Automatic() && state.Garbage)
-               StatusStr = _("[installed,auto-removable]");
-            else if (state.Flags & pkgCache::Flag::Auto)
-               StatusStr = _("[installed,automatic]");
-            else
-               StatusStr = _("[installed]");
-      } else if (P.CurrentVer() && 
-                 policy->GetCandidateVer(P) == V && 
-                 state.Upgradable()) {
-            strprintf(StatusStr, _("[upgradable from: %s]"),
-                      InstalledVerStr.c_str());
-      } else {
-         if (V.ParentPkg()->CurrentState == pkgCache::State::ConfigFiles)
-            StatusStr = _("[residual-config]");
-         else
-            StatusStr = "";
-      }
-      out << std::setiosflags(std::ios::left)
-          << _config->Find("APT::Color::Highlight", "")
-          << name_str 
-          << _config->Find("APT::Color::Neutral", "")
-          << "/" << suite
-          << " "
-          << VersionStr << " " 
-          << GetArchitecture(CacheFile, P);
-      if (StatusStr != "") 
-         out << " " << StatusStr;
-      if (include_summary)
-      {
-         out << std::endl 
-             << "  " << GetShortDescription(CacheFile, records, P)
-             << std::endl;
-      }
+      pkgRecords::Parser & parser = records.Lookup(Desc.FileList());
+      std::string const longdesc = parser.LongDesc();
+      if (longdesc.empty() == false)
+        return SubstVar(longdesc, "\n ", "\n  ");
    }
    }
+   return EmptyDescription;
 }
                                                                        /*}}}*/
 }
                                                                        /*}}}*/
-// ShowList - Show a list                                              /*{{{*/
-// ---------------------------------------------------------------------
-/* This prints out a string of space separated words with a title and 
-   a two space indent line wraped to the current screen width. */
-bool ShowList(ostream &out,string Title,string List,string VersionsList)
+void ListSingleVersion(pkgCacheFile &CacheFile, pkgRecords &records,   /*{{{*/
+                       pkgCache::VerIterator const &V, std::ostream &out,
+                       std::string const &format)
 {
 {
-   if (List.empty() == true)
-      return true;
-   // trim trailing space
-   int NonSpace = List.find_last_not_of(' ');
-   if (NonSpace != -1)
-   {
-      List = List.erase(NonSpace + 1);
-      if (List.empty() == true)
-        return true;
-   }
+   pkgCache::PkgIterator const P = V.ParentPkg();
+   pkgDepCache * const DepCache = CacheFile.GetDepCache();
+   pkgDepCache::StateCache const &state = (*DepCache)[P];
 
 
-   // Acount for the leading space
-   int ScreenWidth = ::ScreenWidth - 3;
-      
-   out << Title << endl;
-   string::size_type Start = 0;
-   string::size_type VersionsStart = 0;
-   while (Start < List.size())
+   std::string output;
+   if (_config->FindB("APT::Cmd::use-format", false))
+      output = _config->Find("APT::Cmd::format", "${db::Status-Abbrev} ${Package} ${Version} ${Origin} ${Description}");
+   else
+      output = format;
+
+   // FIXME: some of these names are really icky – and all is nowhere documented
+   output = SubstVar(output, "${db::Status-Abbrev}", GetFlagsStr(CacheFile, P));
+   output = SubstVar(output, "${Package}", P.Name());
+   std::string const ArchStr = GetArchitecture(CacheFile, P);
+   output = SubstVar(output, "${Architecture}", ArchStr);
+   std::string const InstalledVerStr = GetInstalledVersion(CacheFile, P);
+   output = SubstVar(output, "${installed:Version}", InstalledVerStr);
+   std::string const CandidateVerStr = GetCandidateVersion(CacheFile, P);
+   output = SubstVar(output, "${candidate:Version}", CandidateVerStr);
+   std::string const VersionStr = GetVersion(CacheFile, V);
+   output = SubstVar(output, "${Version}", VersionStr);
+   output = SubstVar(output, "${Origin}", GetArchiveSuite(CacheFile, V));
+
+   std::string StatusStr = "";
+   if (P->CurrentVer != 0)
    {
    {
-      if(_config->FindB("APT::Get::Show-Versions",false) == true &&
-         VersionsList.size() > 0) {
-         string::size_type End;
-         string::size_type VersionsEnd;
-         
-         End = List.find(' ',Start);
-         VersionsEnd = VersionsList.find('\n', VersionsStart);
-
-         out << "   " << string(List,Start,End - Start) << " (" << 
-            string(VersionsList,VersionsStart,VersionsEnd - VersionsStart) << 
-            ")" << endl;
-
-        if (End == string::npos || End < Start)
-           End = Start + ScreenWidth;
-
-         Start = End + 1;
-         VersionsStart = VersionsEnd + 1;
-      } else {
-         string::size_type End;
-
-         if (Start + ScreenWidth >= List.size())
-            End = List.size();
-         else
-            End = List.rfind(' ',Start+ScreenWidth);
-
-         if (End == string::npos || End < Start)
-            End = Start + ScreenWidth;
-         out << "  " << string(List,Start,End - Start) << endl;
-         Start = End + 1;
+      if (P.CurrentVer() == V)
+      {
+        if (state.Upgradable() && state.CandidateVer != NULL)
+           strprintf(StatusStr, _("[installed,upgradable to: %s]"),
+                 CandidateVerStr.c_str());
+        else if (V.Downloadable() == false)
+           StatusStr = _("[installed,local]");
+        else if(V.Automatic() == true && state.Garbage == true)
+           StatusStr = _("[installed,auto-removable]");
+        else if ((state.Flags & pkgCache::Flag::Auto) == pkgCache::Flag::Auto)
+           StatusStr = _("[installed,automatic]");
+        else
+           StatusStr = _("[installed]");
       }
       }
-   }   
-
-   return false;
+      else if (state.CandidateVer == V && state.Upgradable())
+        strprintf(StatusStr, _("[upgradable from: %s]"),
+              InstalledVerStr.c_str());
+   }
+   else if (V.ParentPkg()->CurrentState == pkgCache::State::ConfigFiles)
+      StatusStr = _("[residual-config]");
+   output = SubstVar(output, "${apt:Status}", StatusStr);
+   output = SubstVar(output, "${color:highlight}", _config->Find("APT::Color::Highlight", ""));
+   output = SubstVar(output, "${color:neutral}", _config->Find("APT::Color::Neutral", ""));
+   output = SubstVar(output, "${Description}", GetShortDescription(CacheFile, records, P));
+   output = SubstVar(output, "${LongDescription}", GetLongDescription(CacheFile, records, P));
+   output = SubstVar(output, "${ }${ }", "${ }");
+   output = SubstVar(output, "${ }\n", "\n");
+   output = SubstVar(output, "${ }", " ");
+   if (APT::String::Endswith(output, " ") == true)
+      output.erase(output.length() - 1);
+
+   out << output;
 }
                                                                        /*}}}*/
 // ShowBroken - Debugging aide                                         /*{{{*/
 }
                                                                        /*}}}*/
 // ShowBroken - Debugging aide                                         /*{{{*/
@@ -465,11 +433,9 @@ void ShowBroken(ostream &out, CacheFile &Cache, bool const Now)
       return;
 
    out << _("The following packages have unmet dependencies:") << endl;
       return;
 
    out << _("The following packages have unmet dependencies:") << endl;
-   for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
-   {
-      pkgCache::PkgIterator const I(Cache,Cache.List[J]);
-      ShowBrokenPackage(out, &Cache, I, Now);
-   }
+   SortedPackageUniverse Universe(Cache);
+   for (auto const &Pkg: Universe)
+      ShowBrokenPackage(out, &Cache, Pkg, Now);
 }
 void ShowBroken(ostream &out, pkgCacheFile &Cache, bool const Now)
 {
 }
 void ShowBroken(ostream &out, pkgCacheFile &Cache, bool const Now)
 {
@@ -477,98 +443,64 @@ void ShowBroken(ostream &out, pkgCacheFile &Cache, bool const Now)
       return;
 
    out << _("The following packages have unmet dependencies:") << endl;
       return;
 
    out << _("The following packages have unmet dependencies:") << endl;
-   for (pkgCache::PkgIterator Pkg = Cache->PkgBegin(); Pkg.end() == false; ++Pkg)
+   APT::PackageUniverse Universe(Cache);
+   for (auto const &Pkg: Universe)
       ShowBrokenPackage(out, &Cache, Pkg, Now);
 }
                                                                        /*}}}*/
 // ShowNew - Show packages to newly install                            /*{{{*/
       ShowBrokenPackage(out, &Cache, Pkg, Now);
 }
                                                                        /*}}}*/
 // ShowNew - Show packages to newly install                            /*{{{*/
-// ---------------------------------------------------------------------
-/* */
 void ShowNew(ostream &out,CacheFile &Cache)
 {
 void ShowNew(ostream &out,CacheFile &Cache)
 {
-   /* Print out a list of packages that are going to be installed extra
-      to what the user asked */
-   string List;
-   string VersionsList;
-   for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
-   {
-      pkgCache::PkgIterator I(Cache,Cache.List[J]);
-      if (Cache[I].NewInstall() == true) {
-         List += I.FullName(true) + " ";
-         VersionsList += string(Cache[I].CandVersion) + "\n";
-      }
-   }
-   
-   ShowList(out,_("The following NEW packages will be installed:"),List,VersionsList);
+   SortedPackageUniverse Universe(Cache);
+   ShowList(out,_("The following NEW packages will be installed:"), Universe,
+        [&Cache](pkgCache::PkgIterator const &Pkg) { return Cache[Pkg].NewInstall(); },
+        &PrettyFullName,
+        CandidateVersion(&Cache));
 }
                                                                        /*}}}*/
 // ShowDel - Show packages to delete                                   /*{{{*/
 }
                                                                        /*}}}*/
 // ShowDel - Show packages to delete                                   /*{{{*/
-// ---------------------------------------------------------------------
-/* */
 void ShowDel(ostream &out,CacheFile &Cache)
 {
 void ShowDel(ostream &out,CacheFile &Cache)
 {
-   /* Print out a list of packages that are going to be removed extra
-      to what the user asked */
-   string List;
-   string VersionsList;
-   for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
-   {
-      pkgCache::PkgIterator I(Cache,Cache.List[J]);
-      if (Cache[I].Delete() == true)
-      {
-        if ((Cache[I].iFlags & pkgDepCache::Purge) == pkgDepCache::Purge)
-           List += I.FullName(true) + "* ";
-        else
-           List += I.FullName(true) + " ";
-     
-     VersionsList += string(Cache[I].CandVersion)+ "\n";
-      }
-   }
-   
-   ShowList(out,_("The following packages will be REMOVED:"),List,VersionsList);
+   SortedPackageUniverse Universe(Cache);
+   ShowList(out,_("The following packages will be REMOVED:"), Universe,
+        [&Cache](pkgCache::PkgIterator const &Pkg) { return Cache[Pkg].Delete(); },
+        [&Cache](pkgCache::PkgIterator const &Pkg)
+        {
+           std::string str = PrettyFullName(Pkg);
+           if (((*Cache)[Pkg].iFlags & pkgDepCache::Purge) == pkgDepCache::Purge)
+              str.append("*");
+           return str;
+        },
+        CandidateVersion(&Cache));
 }
                                                                        /*}}}*/
 // ShowKept - Show kept packages                                       /*{{{*/
 }
                                                                        /*}}}*/
 // ShowKept - Show kept packages                                       /*{{{*/
-// ---------------------------------------------------------------------
-/* */
 void ShowKept(ostream &out,CacheFile &Cache)
 {
 void ShowKept(ostream &out,CacheFile &Cache)
 {
-   string List;
-   string VersionsList;
-   for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
-   {    
-      pkgCache::PkgIterator I(Cache,Cache.List[J]);
-      
-      // Not interesting
-      if (Cache[I].Upgrade() == true || Cache[I].Upgradable() == false ||
-         I->CurrentVer == 0 || Cache[I].Delete() == true)
-        continue;
-      
-      List += I.FullName(true) + " ";
-      VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n";
-   }
-   ShowList(out,_("The following packages have been kept back:"),List,VersionsList);
+   SortedPackageUniverse Universe(Cache);
+   ShowList(out,_("The following packages have been kept back:"), Universe,
+        [&Cache](pkgCache::PkgIterator const &Pkg)
+        {
+           return Cache[Pkg].Upgrade() == false &&
+                  Cache[Pkg].Upgradable() == true &&
+                  Pkg->CurrentVer != 0 &&
+                  Cache[Pkg].Delete() == false;
+        },
+        &PrettyFullName,
+        CurrentToCandidateVersion(&Cache));
 }
                                                                        /*}}}*/
 // ShowUpgraded - Show upgraded packages                               /*{{{*/
 }
                                                                        /*}}}*/
 // ShowUpgraded - Show upgraded packages                               /*{{{*/
-// ---------------------------------------------------------------------
-/* */
 void ShowUpgraded(ostream &out,CacheFile &Cache)
 {
 void ShowUpgraded(ostream &out,CacheFile &Cache)
 {
-   string List;
-   string VersionsList;
-   for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
-   {
-      pkgCache::PkgIterator I(Cache,Cache.List[J]);
-      
-      // Not interesting
-      if (Cache[I].Upgrade() == false || Cache[I].NewInstall() == true)
-        continue;
-
-      List += I.FullName(true) + " ";
-      VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n";
-   }
-   ShowList(out,_("The following packages will be upgraded:"),List,VersionsList);
+   SortedPackageUniverse Universe(Cache);
+   ShowList(out,_("The following packages will be upgraded:"), Universe,
+        [&Cache](pkgCache::PkgIterator const &Pkg)
+        {
+           return Cache[Pkg].Upgrade() == true && Cache[Pkg].NewInstall() == false;
+        },
+        &PrettyFullName,
+        CurrentToCandidateVersion(&Cache));
 }
                                                                        /*}}}*/
 // ShowDowngraded - Show downgraded packages                           /*{{{*/
 }
                                                                        /*}}}*/
 // ShowDowngraded - Show downgraded packages                           /*{{{*/
@@ -576,74 +508,73 @@ void ShowUpgraded(ostream &out,CacheFile &Cache)
 /* */
 bool ShowDowngraded(ostream &out,CacheFile &Cache)
 {
 /* */
 bool ShowDowngraded(ostream &out,CacheFile &Cache)
 {
-   string List;
-   string VersionsList;
-   for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
-   {
-      pkgCache::PkgIterator I(Cache,Cache.List[J]);
-      
-      // Not interesting
-      if (Cache[I].Downgrade() == false || Cache[I].NewInstall() == true)
-        continue;
-
-      List += I.FullName(true) + " ";
-      VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n";
-   }
-   return ShowList(out,_("The following packages will be DOWNGRADED:"),List,VersionsList);
+   SortedPackageUniverse Universe(Cache);
+   return ShowList(out,_("The following packages will be DOWNGRADED:"), Universe,
+        [&Cache](pkgCache::PkgIterator const &Pkg)
+        {
+           return Cache[Pkg].Downgrade() == true && Cache[Pkg].NewInstall() == false;
+        },
+        &PrettyFullName,
+        CurrentToCandidateVersion(&Cache));
 }
                                                                        /*}}}*/
 // ShowHold - Show held but changed packages                           /*{{{*/
 }
                                                                        /*}}}*/
 // ShowHold - Show held but changed packages                           /*{{{*/
-// ---------------------------------------------------------------------
-/* */
 bool ShowHold(ostream &out,CacheFile &Cache)
 {
 bool ShowHold(ostream &out,CacheFile &Cache)
 {
-   string List;
-   string VersionsList;
-   for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
-   {
-      pkgCache::PkgIterator I(Cache,Cache.List[J]);
-      if (Cache[I].InstallVer != (pkgCache::Version *)I.CurrentVer() &&
-          I->SelectedState == pkgCache::State::Hold) {
-         List += I.FullName(true) + " ";
-                VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n";
-      }
-   }
-
-   return ShowList(out,_("The following held packages will be changed:"),List,VersionsList);
+   SortedPackageUniverse Universe(Cache);
+   return ShowList(out,_("The following held packages will be changed:"), Universe,
+        [&Cache](pkgCache::PkgIterator const &Pkg)
+        {
+           return Pkg->SelectedState == pkgCache::State::Hold &&
+                  Cache[Pkg].InstallVer != (pkgCache::Version *)Pkg.CurrentVer();
+        },
+        &PrettyFullName,
+        CurrentToCandidateVersion(&Cache));
 }
                                                                        /*}}}*/
 // ShowEssential - Show an essential package warning                   /*{{{*/
 // ---------------------------------------------------------------------
 /* This prints out a warning message that is not to be ignored. It shows
 }
                                                                        /*}}}*/
 // ShowEssential - Show an essential package warning                   /*{{{*/
 // ---------------------------------------------------------------------
 /* This prints out a warning message that is not to be ignored. It shows
-   all essential packages and their dependents that are to be removed. 
+   all essential packages and their dependents that are to be removed.
    It is insanely risky to remove the dependents of an essential package! */
    It is insanely risky to remove the dependents of an essential package! */
+struct APT_HIDDEN PrettyFullNameWithDue {
+   std::map<unsigned long long, pkgCache::PkgIterator> due;
+   PrettyFullNameWithDue() {}
+   std::string operator() (pkgCache::PkgIterator const &Pkg)
+   {
+      std::string const A = PrettyFullName(Pkg);
+      std::map<unsigned long long, pkgCache::PkgIterator>::const_iterator d = due.find(Pkg->ID);
+      if (d == due.end())
+        return A;
+
+      std::string const B = PrettyFullName(d->second);
+      std::ostringstream outstr;
+      ioprintf(outstr, _("%s (due to %s)"), A.c_str(), B.c_str());
+      return outstr.str();
+   }
+};
 bool ShowEssential(ostream &out,CacheFile &Cache)
 {
 bool ShowEssential(ostream &out,CacheFile &Cache)
 {
-   string List;
-   string VersionsList;
-   bool *Added = new bool[Cache->Head().PackageCount];
-   for (unsigned int I = 0; I != Cache->Head().PackageCount; I++)
-      Added[I] = false;
-   
-   for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
+   std::vector<bool> Added(Cache->Head().PackageCount, false);
+   APT::PackageDeque pkglist;
+   PrettyFullNameWithDue withdue;
+
+   SortedPackageUniverse Universe(Cache);
+   for (pkgCache::PkgIterator const &I: Universe)
    {
    {
-      pkgCache::PkgIterator I(Cache,Cache.List[J]);
       if ((I->Flags & pkgCache::Flag::Essential) != pkgCache::Flag::Essential &&
          (I->Flags & pkgCache::Flag::Important) != pkgCache::Flag::Important)
         continue;
       if ((I->Flags & pkgCache::Flag::Essential) != pkgCache::Flag::Essential &&
          (I->Flags & pkgCache::Flag::Important) != pkgCache::Flag::Important)
         continue;
-      
+
       // The essential package is being removed
       // The essential package is being removed
-      if (Cache[I].Delete() == true)
+      if (Cache[I].Delete() == false)
+        continue;
+
+      if (Added[I->ID] == false)
       {
       {
-        if (Added[I->ID] == false)
-        {
-           Added[I->ID] = true;
-           List += I.FullName(true) + " ";
-        //VersionsList += string(Cache[I].CurVersion) + "\n"; ???
-        }
+        Added[I->ID] = true;
+        pkglist.insert(I);
       }
       }
-      else
-        continue;
 
       if (I->CurrentVer == 0)
         continue;
 
       if (I->CurrentVer == 0)
         continue;
@@ -655,27 +586,23 @@ bool ShowEssential(ostream &out,CacheFile &Cache)
         if (D->Type != pkgCache::Dep::PreDepends &&
             D->Type != pkgCache::Dep::Depends)
            continue;
         if (D->Type != pkgCache::Dep::PreDepends &&
             D->Type != pkgCache::Dep::Depends)
            continue;
-        
+
         pkgCache::PkgIterator P = D.SmartTargetPkg();
         if (Cache[P].Delete() == true)
         {
            if (Added[P->ID] == true)
               continue;
            Added[P->ID] = true;
         pkgCache::PkgIterator P = D.SmartTargetPkg();
         if (Cache[P].Delete() == true)
         {
            if (Added[P->ID] == true)
               continue;
            Added[P->ID] = true;
-           
-           char S[300];
-           snprintf(S,sizeof(S),_("%s (due to %s) "),P.FullName(true).c_str(),I.FullName(true).c_str());
-           List += S;
-        //VersionsList += "\n"; ???
-        }       
-      }      
+
+           pkglist.insert(P);
+           withdue.due[P->ID] = I;
+        }
+      }
    }
    }
-   
-   delete [] Added;
    return ShowList(out,_("WARNING: The following essential packages will be removed.\n"
    return ShowList(out,_("WARNING: The following essential packages will be removed.\n"
-                        "This should NOT be done unless you know exactly what you are doing!"),List,VersionsList);
+                        "This should NOT be done unless you know exactly what you are doing!"),
+        pkglist, &AlwaysTrue, withdue, &EmptyString);
 }
 }
-
                                                                        /*}}}*/
 // Stats - Show some statistics                                                /*{{{*/
 // ---------------------------------------------------------------------
                                                                        /*}}}*/
 // Stats - Show some statistics                                                /*{{{*/
 // ---------------------------------------------------------------------
@@ -803,3 +730,33 @@ bool AnalPrompt(const char *Text)
    return false;
 }
                                                                        /*}}}*/
    return false;
 }
                                                                        /*}}}*/
+
+std::string PrettyFullName(pkgCache::PkgIterator const &Pkg)
+{
+   return Pkg.FullName(true);
+}
+std::string CandidateVersion(pkgCacheFile * const Cache, pkgCache::PkgIterator const &Pkg)
+{
+   return (*Cache)[Pkg].CandVersion;
+}
+std::function<std::string(pkgCache::PkgIterator const &)> CandidateVersion(pkgCacheFile * const Cache)
+{
+   return std::bind(static_cast<std::string(*)(pkgCacheFile * const, pkgCache::PkgIterator const&)>(&CandidateVersion), Cache, std::placeholders::_1);
+}
+std::string CurrentToCandidateVersion(pkgCacheFile * const Cache, pkgCache::PkgIterator const &Pkg)
+{
+   return std::string((*Cache)[Pkg].CurVersion) + " => " + (*Cache)[Pkg].CandVersion;
+}
+std::function<std::string(pkgCache::PkgIterator const &)> CurrentToCandidateVersion(pkgCacheFile * const Cache)
+{
+   return std::bind(static_cast<std::string(*)(pkgCacheFile * const, pkgCache::PkgIterator const&)>(&CurrentToCandidateVersion), Cache, std::placeholders::_1);
+}
+bool AlwaysTrue(pkgCache::PkgIterator const &)
+{
+      return true;
+}
+std::string EmptyString(pkgCache::PkgIterator const &)
+{
+   return std::string();
+}
+