#include <signal.h>
#include <sys/ioctl.h>
+#include <sstream>
+
#include <apti18n.h>
/*}}}*/
#endif
}
/*}}}*/
-bool InitOutput() /*{{{*/
+bool InitOutput(std::basic_streambuf<char> * const out) /*{{{*/
{
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)
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;
}
/*}}}*/
+static std::string GetLongDescription(pkgCacheFile &CacheFile, pkgRecords &records, pkgCache::PkgIterator P)/*{{{*/
+{
+ pkgPolicy *policy = CacheFile.GetPolicy();
+
+ pkgCache::VerIterator ver;
+ if (P->CurrentVer != 0)
+ ver = P.CurrentVer();
+ else
+ ver = policy->GetCandidateVer(P);
+
+ std::string const EmptyDescription = "(none)";
+ if(ver.end() == true)
+ return EmptyDescription;
+
+ pkgCache::DescIterator const Desc = ver.TranslatedDescription();
+ if (Desc.end() == false)
+ {
+ pkgRecords::Parser & parser = records.Lookup(Desc.FileList());
+ std::string const longdesc = parser.LongDesc();
+ if (longdesc.empty() == false)
+ return SubstVar(longdesc, "\n ", "\n ");
+ }
+ return EmptyDescription;
+}
+ /*}}}*/
void ListSingleVersion(pkgCacheFile &CacheFile, pkgRecords &records, /*{{{*/
- pkgCache::VerIterator V, std::ostream &out,
- bool include_summary)
+ pkgCache::VerIterator const &V, std::ostream &out,
+ std::string const &format)
{
pkgCache::PkgIterator const P = V.ParentPkg();
pkgDepCache * const DepCache = CacheFile.GetDepCache();
if (_config->FindB("APT::Cmd::use-format", false))
output = _config->Find("APT::Cmd::format", "${db::Status-Abbrev} ${Package} ${Version} ${Origin} ${Description}");
else
- {
- // linux-kernel/unstable version [installed,upradable to: new-version]
- // description
- output = "${color:highlight}${Package}${color:neutral}/${Origin} ${Version} ${Architecture} ${apt:Status}";
- }
+ 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, "${apt:Status}", StatusStr);
output = SubstVar(output, "${color:highlight}", _config->Find("APT::Color::Highlight", ""));
output = SubstVar(output, "${color:neutral}", _config->Find("APT::Color::Neutral", ""));
-
- output = APT::String::Strip(output);
- if (_config->FindB("APT::Cmd::use-format", false) == false)
- {
- if (include_summary)
- output += "\n ${Description}\n";
- }
output = SubstVar(output, "${Description}", GetShortDescription(CacheFile, records, P));
+ if (output.find("${LongDescription}") != string::npos)
+ output = SubstVar(output, "${LongDescription}", GetLongDescription(CacheFile, records, P));
+ output = SubstVar(output, "${ }${ }", "${ }");
+ output = SubstVar(output, "${ }\n", "\n");
+ output = SubstVar(output, "${ }", " ");
+ if (APT::String::Endswith(output, " ") == true)
+ output.erase(output.length() - 1);
out << output;
}
/*}}}*/
-// ShowList - Show a list /*{{{*/
-// ---------------------------------------------------------------------
-/* 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)
-{
- 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;
- }
-
- // 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())
- {
- 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;
- }
- }
-
- return false;
-}
- /*}}}*/
// ShowBroken - Debugging aide /*{{{*/
// ---------------------------------------------------------------------
/* This prints out the names of all the packages that are broken along
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)
{
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 /*{{{*/
-// ---------------------------------------------------------------------
-/* */
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 /*{{{*/
-// ---------------------------------------------------------------------
-/* */
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 /*{{{*/
-// ---------------------------------------------------------------------
-/* */
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 /*{{{*/
-// ---------------------------------------------------------------------
-/* */
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 /*{{{*/
/* */
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 /*{{{*/
-// ---------------------------------------------------------------------
-/* */
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
- 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! */
+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)
{
- 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;
-
+
// 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 (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;
-
- 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"
- "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 /*{{{*/
// ---------------------------------------------------------------------
// YnPrompt - Yes No Prompt. /*{{{*/
// ---------------------------------------------------------------------
/* Returns true on a Yes.*/
-bool YnPrompt(bool Default)
+bool YnPrompt(char const * const Question, bool Default)
{
+ auto const AssumeYes = _config->FindB("APT::Get::Assume-Yes",false);
+ auto const AssumeNo = _config->FindB("APT::Get::Assume-No",false);
+ // if we ask interactively, show warnings/notices before the question
+ if (AssumeYes == false && AssumeNo == false)
+ {
+ if (_config->FindI("quiet",0) > 0)
+ _error->DumpErrors(c2out);
+ else
+ _error->DumpErrors(c2out, GlobalError::DEBUG);
+ }
+
+ c2out << Question << std::flush;
+
/* nl_langinfo does not support LANGUAGE setting, so we unset it here
to have the help-message (hopefully) match the expected characters */
char * language = getenv("LANGUAGE");
free(language);
}
- if (_config->FindB("APT::Get::Assume-Yes",false) == true)
+ if (AssumeYes)
{
// TRANSLATOR: "Yes" answer printed for a yes/no question if --assume-yes is set
c1out << _("Y") << std::endl;
return true;
}
- else if (_config->FindB("APT::Get::Assume-No",false) == true)
+ else if (AssumeNo)
{
// TRANSLATOR: "No" answer printed for a yes/no question if --assume-no is set
c1out << _("N") << std::endl;
// AnalPrompt - Annoying Yes No Prompt. /*{{{*/
// ---------------------------------------------------------------------
/* Returns true on a Yes.*/
-bool AnalPrompt(const char *Text)
+bool AnalPrompt(std::string const &Question, const char *Text)
{
+ if (_config->FindI("quiet",0) > 0)
+ _error->DumpErrors(c2out);
+ else
+ _error->DumpErrors(c2out, GlobalError::DEBUG);
+ c2out << Question << std::flush;
+
char Buf[1024];
std::cin.getline(Buf,sizeof(Buf));
if (strcmp(Buf,Text) == 0)
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();
+}
+