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