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