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