Fix incorrect upgradable listing in "apt list" (thanks to Michael Musenbrock)
[ntk/apt.git] / apt-private / private-output.cc
CommitLineData
b9179170
MV
1// Include files /*{{{*/
2#include<config.h>
3
4#include <apt-pkg/configuration.h>
5#include <apt-pkg/strutl.h>
6#include <apt-pkg/error.h>
7#include <apt-pkg/cachefile.h>
8#include <apt-pkg/pkgrecords.h>
9#include <apt-pkg/policy.h>
453b82a3
DK
10#include <apt-pkg/depcache.h>
11#include <apt-pkg/pkgcache.h>
12#include <apt-pkg/cacheiterators.h>
b9179170 13
453b82a3
DK
14#include <apt-private/private-output.h>
15#include <apt-private/private-cachefile.h>
16
17#include <regex.h>
18#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
b9179170
MV
21#include <iomanip>
22#include <iostream>
b9179170
MV
23#include <langinfo.h>
24#include <unistd.h>
3163087b 25#include <signal.h>
d287a035 26#include <sys/ioctl.h>
b9179170 27
b9179170
MV
28#include <apti18n.h>
29 /*}}}*/
30
31using namespace std;
32
33std::ostream c0out(0);
34std::ostream c1out(0);
35std::ostream c2out(0);
36std::ofstream devnull("/dev/null");
3163087b
MV
37
38
b9179170
MV
39unsigned int ScreenWidth = 80 - 1; /* - 1 for the cursor */
40
3163087b
MV
41// SigWinch - Window size change signal handler /*{{{*/
42// ---------------------------------------------------------------------
43/* */
44static void SigWinch(int)
45{
46 // Riped from GNU ls
47#ifdef TIOCGWINSZ
48 struct winsize ws;
49
50 if (ioctl(1, TIOCGWINSZ, &ws) != -1 && ws.ws_col >= 5)
51 ScreenWidth = ws.ws_col - 1;
52#endif
53}
54 /*}}}*/
ee0167c4 55bool InitOutput() /*{{{*/
b9179170 56{
33b813ce
MV
57 if (!isatty(STDOUT_FILENO) && _config->FindI("quiet", -1) == -1)
58 _config->Set("quiet","1");
59
b9179170
MV
60 c0out.rdbuf(cout.rdbuf());
61 c1out.rdbuf(cout.rdbuf());
62 c2out.rdbuf(cout.rdbuf());
63 if (_config->FindI("quiet",0) > 0)
64 c0out.rdbuf(devnull.rdbuf());
65 if (_config->FindI("quiet",0) > 1)
66 c1out.rdbuf(devnull.rdbuf());
67
3163087b
MV
68 // deal with window size changes
69 signal(SIGWINCH,SigWinch);
70 SigWinch(0);
71
b9179170
MV
72 if(!isatty(1))
73 {
74 _config->Set("APT::Color", "false");
75 _config->Set("APT::Color::Highlight", "");
76 _config->Set("APT::Color::Neutral", "");
77 } else {
78 // Colors
79 _config->CndSet("APT::Color::Highlight", "\x1B[32m");
80 _config->CndSet("APT::Color::Neutral", "\x1B[0m");
81
82 _config->CndSet("APT::Color::Red", "\x1B[31m");
83 _config->CndSet("APT::Color::Green", "\x1B[32m");
84 _config->CndSet("APT::Color::Yellow", "\x1B[33m");
85 _config->CndSet("APT::Color::Blue", "\x1B[34m");
86 _config->CndSet("APT::Color::Magenta", "\x1B[35m");
87 _config->CndSet("APT::Color::Cyan", "\x1B[36m");
88 _config->CndSet("APT::Color::White", "\x1B[37m");
89 }
90
91 return true;
92}
ee0167c4 93 /*}}}*/
65512241 94static std::string GetArchiveSuite(pkgCacheFile &/*CacheFile*/, pkgCache::VerIterator ver) /*{{{*/
b9179170
MV
95{
96 std::string suite = "";
2847bed0 97 if (ver && ver.FileList())
b9179170
MV
98 {
99 pkgCache::VerFileIterator VF = ver.FileList();
100 for (; VF.end() == false ; ++VF)
101 {
960975a1
MV
102 if(VF.File() == NULL || VF.File().Archive() == NULL)
103 suite = suite + "," + _("unknown");
104 else
105 suite = suite + "," + VF.File().Archive();
b9179170
MV
106 //suite = VF.File().Archive();
107 }
108 suite = suite.erase(0, 1);
109 }
110 return suite;
111}
ee0167c4 112 /*}}}*/
c3ccac92 113static std::string GetFlagsStr(pkgCacheFile &CacheFile, pkgCache::PkgIterator P)/*{{{*/
b9179170
MV
114{
115 pkgDepCache *DepCache = CacheFile.GetDepCache();
116 pkgDepCache::StateCache &state = (*DepCache)[P];
117
118 std::string flags_str;
119 if (state.NowBroken())
120 flags_str = "B";
7d1b93d9 121 if (P.CurrentVer() && state.Upgradable() && state.CandidateVer != NULL)
b9179170
MV
122 flags_str = "g";
123 else if (P.CurrentVer() != NULL)
124 flags_str = "i";
125 else
126 flags_str = "-";
127 return flags_str;
128}
ee0167c4 129 /*}}}*/
c3ccac92 130static std::string GetCandidateVersion(pkgCacheFile &CacheFile, pkgCache::PkgIterator P)/*{{{*/
b9179170
MV
131{
132 pkgPolicy *policy = CacheFile.GetPolicy();
133 pkgCache::VerIterator cand = policy->GetCandidateVer(P);
134
135 return cand ? cand.VerStr() : "(none)";
136}
ee0167c4 137 /*}}}*/
65512241 138static std::string GetInstalledVersion(pkgCacheFile &/*CacheFile*/, pkgCache::PkgIterator P)/*{{{*/
b9179170
MV
139{
140 pkgCache::VerIterator inst = P.CurrentVer();
141
142 return inst ? inst.VerStr() : "(none)";
143}
ee0167c4 144 /*}}}*/
65512241 145static std::string GetVersion(pkgCacheFile &/*CacheFile*/, pkgCache::VerIterator V)/*{{{*/
b9179170
MV
146{
147 pkgCache::PkgIterator P = V.ParentPkg();
148 if (V == P.CurrentVer())
149 {
14109555
MV
150 std::string inst_str = DeNull(V.VerStr());
151#if 0 // FIXME: do we want this or something like this?
b9179170
MV
152 pkgDepCache *DepCache = CacheFile.GetDepCache();
153 pkgDepCache::StateCache &state = (*DepCache)[P];
b9179170
MV
154 if (state.Upgradable())
155 return "**"+inst_str;
14109555 156#endif
b9179170
MV
157 return inst_str;
158 }
159
160 if(V)
161 return DeNull(V.VerStr());
162 return "(none)";
163}
ee0167c4 164 /*}}}*/
c3ccac92 165static std::string GetArchitecture(pkgCacheFile &CacheFile, pkgCache::PkgIterator P)/*{{{*/
b9179170
MV
166{
167 pkgPolicy *policy = CacheFile.GetPolicy();
168 pkgCache::VerIterator inst = P.CurrentVer();
169 pkgCache::VerIterator cand = policy->GetCandidateVer(P);
c3ccac92 170
c8259fcd
MV
171 // this may happen for packages in dpkg "deinstall ok config-file" state
172 if (inst.IsGood() == false && cand.IsGood() == false)
173 return P.VersionList().Arch();
174
b9179170
MV
175 return inst ? inst.Arch() : cand.Arch();
176}
ee0167c4 177 /*}}}*/
c3ccac92 178static std::string GetShortDescription(pkgCacheFile &CacheFile, pkgRecords &records, pkgCache::PkgIterator P)/*{{{*/
b9179170
MV
179{
180 pkgPolicy *policy = CacheFile.GetPolicy();
181
182 pkgCache::VerIterator ver;
183 if (P.CurrentVer())
184 ver = P.CurrentVer();
185 else
186 ver = policy->GetCandidateVer(P);
187
188 std::string ShortDescription = "(none)";
189 if(ver)
190 {
191 pkgCache::DescIterator Desc = ver.TranslatedDescription();
192 pkgRecords::Parser & parser = records.Lookup(Desc.FileList());
193
194 ShortDescription = parser.ShortDesc();
195 }
196 return ShortDescription;
197}
ee0167c4
DK
198 /*}}}*/
199void ListSingleVersion(pkgCacheFile &CacheFile, pkgRecords &records, /*{{{*/
500347df
MV
200 pkgCache::VerIterator V, std::ostream &out,
201 bool include_summary)
b9179170
MV
202{
203 pkgCache::PkgIterator P = V.ParentPkg();
204
205 pkgDepCache *DepCache = CacheFile.GetDepCache();
206 pkgDepCache::StateCache &state = (*DepCache)[P];
207
208 std::string suite = GetArchiveSuite(CacheFile, V);
209 std::string name_str = P.Name();
210
211 if (_config->FindB("APT::Cmd::use-format", false))
212 {
213 std::string format = _config->Find("APT::Cmd::format", "${db::Status-Abbrev} ${Package} ${Version} ${Origin} ${Description}");
214 std::string output = format;
215
216 output = SubstVar(output, "${db::Status-Abbrev}", GetFlagsStr(CacheFile, P));
217 output = SubstVar(output, "${Package}", name_str);
218 output = SubstVar(output, "${installed:Version}", GetInstalledVersion(CacheFile, P));
219 output = SubstVar(output, "${candidate:Version}", GetCandidateVersion(CacheFile, P));
220 output = SubstVar(output, "${Version}", GetVersion(CacheFile, V));
221 output = SubstVar(output, "${Description}", GetShortDescription(CacheFile, records, P));
222 output = SubstVar(output, "${Origin}", GetArchiveSuite(CacheFile, V));
6763aaec 223 out << output;
b9179170
MV
224 } else {
225 // raring/linux-kernel version [upradable: new-version]
226 // description
227 pkgPolicy *policy = CacheFile.GetPolicy();
4afa7d18
MV
228 std::string VersionStr = GetVersion(CacheFile, V);
229 std::string CandidateVerStr = GetCandidateVersion(CacheFile, P);
230 std::string InstalledVerStr = GetInstalledVersion(CacheFile, P);
231 std::string StatusStr;
d059cc26
MV
232 if(P.CurrentVer() == V &&
233 state.Upgradable() &&
234 state.CandidateVer != NULL &&
235 policy->GetCandidateVer(P) != P.CurrentVer())
7d1b93d9 236 {
4afa7d18
MV
237 strprintf(StatusStr, _("[installed,upgradable to: %s]"),
238 CandidateVerStr.c_str());
b9179170 239 } else if (P.CurrentVer() == V) {
b9179170 240 if(!V.Downloadable())
4afa7d18 241 StatusStr = _("[installed,local]");
b9179170
MV
242 else
243 if(V.Automatic() && state.Garbage)
4afa7d18 244 StatusStr = _("[installed,auto-removable]");
b9179170 245 else if (state.Flags & pkgCache::Flag::Auto)
4afa7d18 246 StatusStr = _("[installed,automatic]");
b9179170 247 else
4afa7d18 248 StatusStr = _("[installed]");
b9179170
MV
249 } else if (P.CurrentVer() &&
250 policy->GetCandidateVer(P) == V &&
251 state.Upgradable()) {
4afa7d18
MV
252 strprintf(StatusStr, _("[upgradable from: %s]"),
253 InstalledVerStr.c_str());
b9179170
MV
254 } else {
255 if (V.ParentPkg()->CurrentState == pkgCache::State::ConfigFiles)
4afa7d18 256 StatusStr = _("[residual-config]");
b9179170 257 else
4afa7d18 258 StatusStr = "";
b9179170 259 }
4afa7d18
MV
260 out << std::setiosflags(std::ios::left)
261 << _config->Find("APT::Color::Highlight", "")
262 << name_str
263 << _config->Find("APT::Color::Neutral", "")
264 << "/" << suite
265 << " "
266 << VersionStr << " "
267 << GetArchitecture(CacheFile, P);
268 if (StatusStr != "")
269 out << " " << StatusStr;
500347df
MV
270 if (include_summary)
271 {
272 out << std::endl
14109555 273 << " " << GetShortDescription(CacheFile, records, P)
500347df
MV
274 << std::endl;
275 }
b9179170
MV
276 }
277}
ee0167c4 278 /*}}}*/
b9179170
MV
279// ShowList - Show a list /*{{{*/
280// ---------------------------------------------------------------------
281/* This prints out a string of space separated words with a title and
282 a two space indent line wraped to the current screen width. */
283bool ShowList(ostream &out,string Title,string List,string VersionsList)
284{
285 if (List.empty() == true)
286 return true;
287 // trim trailing space
288 int NonSpace = List.find_last_not_of(' ');
289 if (NonSpace != -1)
290 {
291 List = List.erase(NonSpace + 1);
292 if (List.empty() == true)
293 return true;
294 }
295
296 // Acount for the leading space
297 int ScreenWidth = ::ScreenWidth - 3;
298
299 out << Title << endl;
300 string::size_type Start = 0;
301 string::size_type VersionsStart = 0;
302 while (Start < List.size())
303 {
304 if(_config->FindB("APT::Get::Show-Versions",false) == true &&
305 VersionsList.size() > 0) {
306 string::size_type End;
307 string::size_type VersionsEnd;
308
309 End = List.find(' ',Start);
310 VersionsEnd = VersionsList.find('\n', VersionsStart);
311
312 out << " " << string(List,Start,End - Start) << " (" <<
313 string(VersionsList,VersionsStart,VersionsEnd - VersionsStart) <<
314 ")" << endl;
315
316 if (End == string::npos || End < Start)
317 End = Start + ScreenWidth;
318
319 Start = End + 1;
320 VersionsStart = VersionsEnd + 1;
321 } else {
322 string::size_type End;
323
324 if (Start + ScreenWidth >= List.size())
325 End = List.size();
326 else
327 End = List.rfind(' ',Start+ScreenWidth);
328
329 if (End == string::npos || End < Start)
330 End = Start + ScreenWidth;
331 out << " " << string(List,Start,End - Start) << endl;
332 Start = End + 1;
333 }
334 }
335
336 return false;
337}
338 /*}}}*/
339// ShowBroken - Debugging aide /*{{{*/
340// ---------------------------------------------------------------------
341/* This prints out the names of all the packages that are broken along
342 with the name of each each broken dependency and a quite version
343 description.
344
345 The output looks like:
346 The following packages have unmet dependencies:
347 exim: Depends: libc6 (>= 2.1.94) but 2.1.3-10 is to be installed
348 Depends: libldap2 (>= 2.0.2-2) but it is not going to be installed
349 Depends: libsasl7 but it is not going to be installed
350 */
d39d7f88 351static void ShowBrokenPackage(ostream &out, pkgCacheFile * const Cache, pkgCache::PkgIterator const &Pkg, bool const Now)
b9179170 352{
d39d7f88
DK
353 if (Now == true)
354 {
355 if ((*Cache)[Pkg].NowBroken() == false)
356 return;
357 }
358 else
359 {
360 if ((*Cache)[Pkg].InstBroken() == false)
361 return;
362 }
363
364 // Print out each package and the failed dependencies
365 out << " " << Pkg.FullName(true) << " :";
366 unsigned const Indent = Pkg.FullName(true).size() + 3;
367 bool First = true;
368 pkgCache::VerIterator Ver;
369
370 if (Now == true)
371 Ver = Pkg.CurrentVer();
372 else
373 Ver = (*Cache)[Pkg].InstVerIter(*Cache);
374
375 if (Ver.end() == true)
376 {
377 out << endl;
b9179170 378 return;
d39d7f88 379 }
b9179170 380
d39d7f88 381 for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false;)
b9179170 382 {
d39d7f88
DK
383 // Compute a single dependency element (glob or)
384 pkgCache::DepIterator Start;
385 pkgCache::DepIterator End;
386 D.GlobOr(Start,End); // advances D
387
388 if ((*Cache)->IsImportantDep(End) == false)
389 continue;
390
b9179170
MV
391 if (Now == true)
392 {
d39d7f88 393 if (((*Cache)[End] & pkgDepCache::DepGNow) == pkgDepCache::DepGNow)
b9179170
MV
394 continue;
395 }
396 else
397 {
d39d7f88 398 if (((*Cache)[End] & pkgDepCache::DepGInstall) == pkgDepCache::DepGInstall)
b9179170
MV
399 continue;
400 }
d39d7f88
DK
401
402 bool FirstOr = true;
403 while (1)
b9179170 404 {
d39d7f88
DK
405 if (First == false)
406 for (unsigned J = 0; J != Indent; J++)
407 out << ' ';
408 First = false;
b9179170 409
d39d7f88 410 if (FirstOr == false)
b9179170 411 {
d39d7f88
DK
412 for (unsigned J = 0; J != strlen(End.DepType()) + 3; J++)
413 out << ' ';
b9179170
MV
414 }
415 else
d39d7f88
DK
416 out << ' ' << End.DepType() << ": ";
417 FirstOr = false;
418
419 out << Start.TargetPkg().FullName(true);
420
421 // Show a quick summary of the version requirements
422 if (Start.TargetVer() != 0)
423 out << " (" << Start.CompType() << " " << Start.TargetVer() << ")";
424
425 /* Show a summary of the target package if possible. In the case
426 of virtual packages we show nothing */
427 pkgCache::PkgIterator Targ = Start.TargetPkg();
428 if (Targ->ProvidesList == 0)
b9179170 429 {
d39d7f88
DK
430 out << ' ';
431 pkgCache::VerIterator Ver = (*Cache)[Targ].InstVerIter(*Cache);
432 if (Now == true)
433 Ver = Targ.CurrentVer();
b9179170 434
d39d7f88 435 if (Ver.end() == false)
b9179170 436 {
d39d7f88
DK
437 if (Now == true)
438 ioprintf(out,_("but %s is installed"),Ver.VerStr());
439 else
440 ioprintf(out,_("but %s is to be installed"),Ver.VerStr());
b9179170
MV
441 }
442 else
b9179170 443 {
d39d7f88 444 if ((*Cache)[Targ].CandidateVerIter(*Cache).end() == true)
b9179170 445 {
d39d7f88
DK
446 if (Targ->ProvidesList == 0)
447 out << _("but it is not installable");
b9179170 448 else
d39d7f88
DK
449 out << _("but it is a virtual package");
450 }
b9179170 451 else
d39d7f88 452 out << (Now?_("but it is not installed"):_("but it is not going to be installed"));
b9179170 453 }
d39d7f88
DK
454 }
455
456 if (Start != End)
457 out << _(" or");
458 out << endl;
459
460 if (Start == End)
461 break;
462 ++Start;
463 }
464 }
465}
466void ShowBroken(ostream &out, CacheFile &Cache, bool const Now)
467{
468 if (Cache->BrokenCount() == 0)
469 return;
470
471 out << _("The following packages have unmet dependencies:") << endl;
472 for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
473 {
474 pkgCache::PkgIterator const I(Cache,Cache.List[J]);
475 ShowBrokenPackage(out, &Cache, I, Now);
476 }
477}
478void ShowBroken(ostream &out, pkgCacheFile &Cache, bool const Now)
479{
480 if (Cache->BrokenCount() == 0)
481 return;
482
483 out << _("The following packages have unmet dependencies:") << endl;
484 for (pkgCache::PkgIterator Pkg = Cache->PkgBegin(); Pkg.end() == false; ++Pkg)
485 ShowBrokenPackage(out, &Cache, Pkg, Now);
b9179170
MV
486}
487 /*}}}*/
488// ShowNew - Show packages to newly install /*{{{*/
489// ---------------------------------------------------------------------
490/* */
491void ShowNew(ostream &out,CacheFile &Cache)
492{
493 /* Print out a list of packages that are going to be installed extra
494 to what the user asked */
495 string List;
496 string VersionsList;
497 for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
498 {
499 pkgCache::PkgIterator I(Cache,Cache.List[J]);
500 if (Cache[I].NewInstall() == true) {
501 List += I.FullName(true) + " ";
502 VersionsList += string(Cache[I].CandVersion) + "\n";
503 }
504 }
505
506 ShowList(out,_("The following NEW packages will be installed:"),List,VersionsList);
507}
508 /*}}}*/
509// ShowDel - Show packages to delete /*{{{*/
510// ---------------------------------------------------------------------
511/* */
512void ShowDel(ostream &out,CacheFile &Cache)
513{
514 /* Print out a list of packages that are going to be removed extra
515 to what the user asked */
516 string List;
517 string VersionsList;
518 for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
519 {
520 pkgCache::PkgIterator I(Cache,Cache.List[J]);
521 if (Cache[I].Delete() == true)
522 {
523 if ((Cache[I].iFlags & pkgDepCache::Purge) == pkgDepCache::Purge)
524 List += I.FullName(true) + "* ";
525 else
526 List += I.FullName(true) + " ";
527
528 VersionsList += string(Cache[I].CandVersion)+ "\n";
529 }
530 }
531
532 ShowList(out,_("The following packages will be REMOVED:"),List,VersionsList);
533}
534 /*}}}*/
535// ShowKept - Show kept packages /*{{{*/
536// ---------------------------------------------------------------------
537/* */
538void ShowKept(ostream &out,CacheFile &Cache)
539{
540 string List;
541 string VersionsList;
542 for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
543 {
544 pkgCache::PkgIterator I(Cache,Cache.List[J]);
545
546 // Not interesting
547 if (Cache[I].Upgrade() == true || Cache[I].Upgradable() == false ||
548 I->CurrentVer == 0 || Cache[I].Delete() == true)
549 continue;
550
551 List += I.FullName(true) + " ";
552 VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n";
553 }
554 ShowList(out,_("The following packages have been kept back:"),List,VersionsList);
555}
556 /*}}}*/
557// ShowUpgraded - Show upgraded packages /*{{{*/
558// ---------------------------------------------------------------------
559/* */
560void ShowUpgraded(ostream &out,CacheFile &Cache)
561{
562 string List;
563 string VersionsList;
564 for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
565 {
566 pkgCache::PkgIterator I(Cache,Cache.List[J]);
567
568 // Not interesting
569 if (Cache[I].Upgrade() == false || Cache[I].NewInstall() == true)
570 continue;
571
572 List += I.FullName(true) + " ";
573 VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n";
574 }
575 ShowList(out,_("The following packages will be upgraded:"),List,VersionsList);
576}
577 /*}}}*/
578// ShowDowngraded - Show downgraded packages /*{{{*/
579// ---------------------------------------------------------------------
580/* */
581bool ShowDowngraded(ostream &out,CacheFile &Cache)
582{
583 string List;
584 string VersionsList;
585 for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
586 {
587 pkgCache::PkgIterator I(Cache,Cache.List[J]);
588
589 // Not interesting
590 if (Cache[I].Downgrade() == false || Cache[I].NewInstall() == true)
591 continue;
592
593 List += I.FullName(true) + " ";
594 VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n";
595 }
596 return ShowList(out,_("The following packages will be DOWNGRADED:"),List,VersionsList);
597}
598 /*}}}*/
599// ShowHold - Show held but changed packages /*{{{*/
600// ---------------------------------------------------------------------
601/* */
602bool ShowHold(ostream &out,CacheFile &Cache)
603{
604 string List;
605 string VersionsList;
606 for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
607 {
608 pkgCache::PkgIterator I(Cache,Cache.List[J]);
609 if (Cache[I].InstallVer != (pkgCache::Version *)I.CurrentVer() &&
610 I->SelectedState == pkgCache::State::Hold) {
611 List += I.FullName(true) + " ";
612 VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n";
613 }
614 }
615
616 return ShowList(out,_("The following held packages will be changed:"),List,VersionsList);
617}
618 /*}}}*/
619// ShowEssential - Show an essential package warning /*{{{*/
620// ---------------------------------------------------------------------
621/* This prints out a warning message that is not to be ignored. It shows
622 all essential packages and their dependents that are to be removed.
623 It is insanely risky to remove the dependents of an essential package! */
624bool ShowEssential(ostream &out,CacheFile &Cache)
625{
626 string List;
627 string VersionsList;
628 bool *Added = new bool[Cache->Head().PackageCount];
629 for (unsigned int I = 0; I != Cache->Head().PackageCount; I++)
630 Added[I] = false;
631
632 for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
633 {
634 pkgCache::PkgIterator I(Cache,Cache.List[J]);
635 if ((I->Flags & pkgCache::Flag::Essential) != pkgCache::Flag::Essential &&
636 (I->Flags & pkgCache::Flag::Important) != pkgCache::Flag::Important)
637 continue;
638
639 // The essential package is being removed
640 if (Cache[I].Delete() == true)
641 {
642 if (Added[I->ID] == false)
643 {
644 Added[I->ID] = true;
645 List += I.FullName(true) + " ";
646 //VersionsList += string(Cache[I].CurVersion) + "\n"; ???
647 }
648 }
649 else
650 continue;
651
652 if (I->CurrentVer == 0)
653 continue;
654
655 // Print out any essential package depenendents that are to be removed
656 for (pkgCache::DepIterator D = I.CurrentVer().DependsList(); D.end() == false; ++D)
657 {
658 // Skip everything but depends
659 if (D->Type != pkgCache::Dep::PreDepends &&
660 D->Type != pkgCache::Dep::Depends)
661 continue;
662
663 pkgCache::PkgIterator P = D.SmartTargetPkg();
664 if (Cache[P].Delete() == true)
665 {
666 if (Added[P->ID] == true)
667 continue;
668 Added[P->ID] = true;
669
670 char S[300];
671 snprintf(S,sizeof(S),_("%s (due to %s) "),P.FullName(true).c_str(),I.FullName(true).c_str());
672 List += S;
673 //VersionsList += "\n"; ???
674 }
675 }
676 }
677
678 delete [] Added;
679 return ShowList(out,_("WARNING: The following essential packages will be removed.\n"
680 "This should NOT be done unless you know exactly what you are doing!"),List,VersionsList);
681}
682
683 /*}}}*/
684// Stats - Show some statistics /*{{{*/
685// ---------------------------------------------------------------------
686/* */
687void Stats(ostream &out,pkgDepCache &Dep)
688{
689 unsigned long Upgrade = 0;
690 unsigned long Downgrade = 0;
691 unsigned long Install = 0;
692 unsigned long ReInstall = 0;
693 for (pkgCache::PkgIterator I = Dep.PkgBegin(); I.end() == false; ++I)
694 {
695 if (Dep[I].NewInstall() == true)
696 Install++;
697 else
698 {
699 if (Dep[I].Upgrade() == true)
700 Upgrade++;
701 else
702 if (Dep[I].Downgrade() == true)
703 Downgrade++;
704 }
705
706 if (Dep[I].Delete() == false && (Dep[I].iFlags & pkgDepCache::ReInstall) == pkgDepCache::ReInstall)
707 ReInstall++;
708 }
709
710 ioprintf(out,_("%lu upgraded, %lu newly installed, "),
711 Upgrade,Install);
712
713 if (ReInstall != 0)
714 ioprintf(out,_("%lu reinstalled, "),ReInstall);
715 if (Downgrade != 0)
716 ioprintf(out,_("%lu downgraded, "),Downgrade);
717
718 ioprintf(out,_("%lu to remove and %lu not upgraded.\n"),
719 Dep.DelCount(),Dep.KeepCount());
720
721 if (Dep.BadCount() != 0)
722 ioprintf(out,_("%lu not fully installed or removed.\n"),
723 Dep.BadCount());
724}
725 /*}}}*/
726// YnPrompt - Yes No Prompt. /*{{{*/
727// ---------------------------------------------------------------------
728/* Returns true on a Yes.*/
729bool YnPrompt(bool Default)
730{
731 /* nl_langinfo does not support LANGUAGE setting, so we unset it here
732 to have the help-message (hopefully) match the expected characters */
733 char * language = getenv("LANGUAGE");
734 if (language != NULL)
735 language = strdup(language);
736 if (language != NULL)
737 unsetenv("LANGUAGE");
738
739 if (Default == true)
740 // TRANSLATOR: Yes/No question help-text: defaulting to Y[es]
741 // e.g. "Do you want to continue? [Y/n] "
742 // The user has to answer with an input matching the
743 // YESEXPR/NOEXPR defined in your l10n.
744 c2out << " " << _("[Y/n]") << " " << std::flush;
745 else
746 // TRANSLATOR: Yes/No question help-text: defaulting to N[o]
747 // e.g. "Should this file be removed? [y/N] "
748 // The user has to answer with an input matching the
749 // YESEXPR/NOEXPR defined in your l10n.
750 c2out << " " << _("[y/N]") << " " << std::flush;
751
752 if (language != NULL)
753 {
754 setenv("LANGUAGE", language, 0);
755 free(language);
756 }
757
758 if (_config->FindB("APT::Get::Assume-Yes",false) == true)
759 {
760 // TRANSLATOR: "Yes" answer printed for a yes/no question if --assume-yes is set
761 c1out << _("Y") << std::endl;
762 return true;
763 }
764 else if (_config->FindB("APT::Get::Assume-No",false) == true)
765 {
766 // TRANSLATOR: "No" answer printed for a yes/no question if --assume-no is set
767 c1out << _("N") << std::endl;
768 return false;
769 }
770
771 char response[1024] = "";
772 std::cin.getline(response, sizeof(response));
773
774 if (!std::cin)
775 return false;
776
777 if (strlen(response) == 0)
778 return Default;
779
780 regex_t Pattern;
781 int Res;
782
783 Res = regcomp(&Pattern, nl_langinfo(YESEXPR),
784 REG_EXTENDED|REG_ICASE|REG_NOSUB);
785
786 if (Res != 0) {
787 char Error[300];
788 regerror(Res,&Pattern,Error,sizeof(Error));
789 return _error->Error(_("Regex compilation error - %s"),Error);
790 }
791
792 Res = regexec(&Pattern, response, 0, NULL, 0);
793 if (Res == 0)
794 return true;
795 return false;
796}
797 /*}}}*/
798// AnalPrompt - Annoying Yes No Prompt. /*{{{*/
799// ---------------------------------------------------------------------
800/* Returns true on a Yes.*/
801bool AnalPrompt(const char *Text)
802{
803 char Buf[1024];
804 std::cin.getline(Buf,sizeof(Buf));
805 if (strcmp(Buf,Text) == 0)
806 return true;
807 return false;
808}
809 /*}}}*/