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