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