Add bunch of missing includes to fix build with gcc 4.7
[apt.git] / cmdline / cmdline.cc
1 // -*- mode: c++; mode: fold -*-
2 #include <apt-pkg/configuration.h>
3 #include <apt-pkg/error.h>
4 #include <apt-pkg/acquire.h>
5 #include <apt-pkg/sptr.h>
6
7 #include <config.h>
8 #include <apti18n.h>
9
10 #include "cmdline.h"
11
12 #include <regex.h>
13 #include <sys/stat.h>
14 #include <sys/ioctl.h>
15 #include <fnmatch.h>
16 #include <langinfo.h>
17
18 using namespace std;
19
20 // YnPrompt - Yes No Prompt.                                            /*{{{*/
21 // ---------------------------------------------------------------------
22 /* Returns true on a Yes.*/
23 bool YnPrompt()
24 {
25    if (_config->FindB("APT::Get::Assume-Yes",false) == true)
26    {
27       c1out << _("Y") << endl;
28       return true;
29    }
30
31    char response[1024] = "";
32    cin.getline(response, sizeof(response));
33
34    if (!cin)
35       return false;
36
37    if (strlen(response) == 0)
38       return true;
39
40    regex_t Pattern;
41    int Res;
42
43    Res = regcomp(&Pattern, nl_langinfo(YESEXPR),
44                  REG_EXTENDED|REG_ICASE|REG_NOSUB);
45
46    if (Res != 0) {
47       char Error[300];        
48       regerror(Res,&Pattern,Error,sizeof(Error));
49       return _error->Error(_("Regex compilation error - %s"),Error);
50    }
51    
52    Res = regexec(&Pattern, response, 0, NULL, 0);
53    if (Res == 0)
54       return true;
55    return false;
56 }
57                                                                         /*}}}*/
58 // AnalPrompt - Annoying Yes No Prompt.                                 /*{{{*/
59 // ---------------------------------------------------------------------
60 /* Returns true on a Yes.*/
61 bool AnalPrompt(const char *Text)
62 {
63    char Buf[1024];
64    cin.getline(Buf,sizeof(Buf));
65    if (strcmp(Buf,Text) == 0)
66       return true;
67    return false;
68 }
69                                                                         /*}}}*/
70 // ShowList - Show a list                                               /*{{{*/
71 // ---------------------------------------------------------------------
72 /* This prints out a string of space separated words with a title and 
73    a two space indent line wraped to the current screen width. */
74 bool ShowList(ostream &out,string Title,string List,string VersionsList)
75 {
76    if (List.empty() == true)
77       return true;
78    // trim trailing space
79    int NonSpace = List.find_last_not_of(' ');
80    if (NonSpace != -1)
81    {
82       List = List.erase(NonSpace + 1);
83       if (List.empty() == true)
84          return true;
85    }
86
87    // Acount for the leading space
88    int ScreenWidth = ::ScreenWidth - 3;
89       
90    out << Title << endl;
91    string::size_type Start = 0;
92    string::size_type VersionsStart = 0;
93    while (Start < List.size())
94    {
95       if(_config->FindB("APT::Get::Show-Versions",false) == true &&
96          VersionsList.size() > 0) {
97          string::size_type End;
98          string::size_type VersionsEnd;
99          
100          End = List.find(' ',Start);
101          VersionsEnd = VersionsList.find('\n', VersionsStart);
102
103          out << "   " << string(List,Start,End - Start) << " (" << 
104             string(VersionsList,VersionsStart,VersionsEnd - VersionsStart) << 
105             ")";
106
107          // simple workaround to print a replacement string if it's there
108          if (End != string::npos && End+1 < List.size() && List[End+1] == '(') {
109             Start = End;
110             End = List.find(')', Start);
111             if (End != string::npos) {
112                out << string(List,Start,End - Start + 1);
113                // Skip all spaces after a replacement string
114                while (End+1 < List.size() && List[End+1] <= ' ')
115                   End++;
116             }
117          }
118
119          out << endl;
120
121          if (End == string::npos || End < Start)
122             End = Start + ScreenWidth;
123
124          Start = End + 1;
125          VersionsStart = VersionsEnd + 1;
126       } else {
127          string::size_type End;
128
129          if (Start + ScreenWidth >= List.size())
130             End = List.size();
131          else
132             End = List.rfind(' ',Start+ScreenWidth);
133
134          if (End == string::npos || End < Start)
135             End = Start + ScreenWidth;
136          out << "  " << string(List,Start,End - Start) << endl;
137          Start = End + 1;
138       }
139    }   
140
141    return false;
142 }
143
144 const char *op2str(int op)
145 {
146    switch (op & 0x0f)
147    {
148       case pkgCache::Dep::LessEq: return "<=";
149       case pkgCache::Dep::GreaterEq: return ">=";
150       case pkgCache::Dep::Less: return "<";
151       case pkgCache::Dep::Greater: return ">";
152       case pkgCache::Dep::Equals: return "=";
153       case pkgCache::Dep::NotEquals: return "!";
154       default: return "";
155    }
156 }
157
158 // SigWinch - Window size change signal handler                         /*{{{*/
159 // ---------------------------------------------------------------------
160 /* */
161 void SigWinch(int)
162 {
163    // Riped from GNU ls
164 #ifdef TIOCGWINSZ
165    struct winsize ws;
166
167    if (ioctl(1, TIOCGWINSZ, &ws) != -1 && ws.ws_col >= 5)
168       ScreenWidth = ws.ws_col - 1;
169 #endif
170 }
171
172 // CacheFile::NameComp - QSort compare by name                          /*{{{*/
173 // ---------------------------------------------------------------------
174 /* */
175 pkgCache *cmdCacheFile::SortCache = 0;
176 int cmdCacheFile::NameComp(const void *a,const void *b)
177 {
178    if (*(pkgCache::Package **)a == 0 || *(pkgCache::Package **)b == 0)
179       return *(pkgCache::Package **)a - *(pkgCache::Package **)b;
180
181    const pkgCache::Package &A = **(pkgCache::Package **)a;
182    const pkgCache::Package &B = **(pkgCache::Package **)b;
183
184    return strcmp(SortCache->StrP + A.Name,SortCache->StrP + B.Name);
185 }
186                                                                         /*}}}*/
187 // CacheFile::Sort - Sort by name                                       /*{{{*/
188 // ---------------------------------------------------------------------
189 /* */
190 void cmdCacheFile::Sort()
191 {
192    delete [] List;
193    List = new pkgCache::Package *[Cache->Head().PackageCount];
194    memset(List,0,sizeof(*List)*Cache->Head().PackageCount);
195    pkgCache::PkgIterator I = Cache->PkgBegin();
196    for (;I.end() != true; I++)
197       List[I->ID] = I;
198
199    SortCache = *this;
200    qsort(List,Cache->Head().PackageCount,sizeof(*List),NameComp);
201 }
202
203 cmdCacheFile::~cmdCacheFile()
204 {
205    if (List) {
206       delete [] List;
207    }
208 }
209
210 // ShowBroken - Debugging aide                                          /*{{{*/
211 // ---------------------------------------------------------------------
212 /* This prints out the names of all the packages that are broken along
213    with the name of each each broken dependency and a quite version 
214    description.
215    
216    The output looks like:
217  The following packages have unmet dependencies:
218      exim: Depends: libc6 (>= 2.1.94) but 2.1.3-10 is to be installed
219            Depends: libldap2 (>= 2.0.2-2) but it is not going to be installed
220            Depends: libsasl7 but it is not going to be installed   
221  */
222 void ShowBroken(ostream &out,cmdCacheFile &Cache,bool Now,pkgDepCache::State *State)
223 {
224    out << _("The following packages have unmet dependencies:") << endl;
225    for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
226    {
227       pkgCache::PkgIterator I(Cache,Cache.List[J]);
228       
229       if (Now == true)
230       {
231          if (Cache[I].NowBroken() == false)
232             continue;
233       }
234       else
235       {
236          if (Cache[I].InstBroken() == false)
237             continue;
238       }
239       
240       // Print out each package and the failed dependencies
241       out <<"  " <<  I.Name() << ":";
242       size_t Indent = strlen(I.Name()) + 3;
243       bool First = true;
244       pkgCache::VerIterator Ver;
245       
246       if (Now == true)
247          Ver = I.CurrentVer();
248       else
249          Ver = Cache[I].InstVerIter(Cache);
250       
251       if (Ver.end() == true)
252       {
253          out << endl;
254          continue;
255       }
256       
257       for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false;)
258       {
259          // Compute a single dependency element (glob or)
260          pkgCache::DepIterator Start;
261          pkgCache::DepIterator End;
262          D.GlobOr(Start,End);
263
264          // CNC:2003-02-22 - IsImportantDep() currently calls IsCritical(), so
265          //                  these two are currently doing the same thing. Check
266          //                  comments in IsImportantDep() definition.
267 #if 0
268          if (Cache->IsImportantDep(End) == false)
269             continue;
270 #else
271          if (End.IsCritical() == false)
272             continue;
273 #endif
274          
275          if (Now == true)
276          {
277             if ((Cache[End] & pkgDepCache::DepGNow) == pkgDepCache::DepGNow)
278                continue;
279          }
280          else
281          {
282             if ((Cache[End] & pkgDepCache::DepGInstall) == pkgDepCache::DepGInstall)
283                continue;
284          }
285          
286          bool FirstOr = true;
287          while (1)
288          {
289             if (First == false)
290                for (unsigned J = 0; J != Indent; J++)
291                   out << ' ';
292             First = false;
293
294             if (FirstOr == false)
295             {
296                for (size_t J = 0; J != strlen(End.DepType()) + 3; J++)
297                   out << ' ';
298             }
299             else
300                out << ' ' << End.DepType() << ": ";
301             FirstOr = false;
302             
303             out << Start.TargetPkg().Name();
304          
305             // Show a quick summary of the version requirements
306             if (Start.TargetVer() != 0)
307                out << " (" << Start.CompType() << " " << Start.TargetVer() << ")";
308             
309             /* Show a summary of the target package if possible. In the case
310                of virtual packages we show nothing */    
311             pkgCache::PkgIterator Targ = Start.TargetPkg();
312             if (Targ->ProvidesList == 0)
313             {
314                out << ' ';
315                pkgCache::VerIterator Ver = Cache[Targ].InstVerIter(Cache);
316                if (Now == true)
317                   Ver = Targ.CurrentVer();
318                     
319                if (Ver.end() == false)
320                {
321                   if (Now == true)
322                      ioprintf(out,_("but %s is installed"),Ver.VerStr());
323                   else
324                      ioprintf(out,_("but %s is to be installed"),Ver.VerStr());
325                }               
326                else
327                {
328                   if (Cache[Targ].CandidateVerIter(Cache).end() == true)
329                   {
330                      if (Targ->ProvidesList == 0)
331                         out << _("but it is not installable");
332                      else
333                         out << _("but it is a virtual package");
334                   }               
335                   else
336                      out << (Now?_("but it is not installed"):_("but it is not going to be installed"));
337                }               
338             }
339             
340             if (Start != End)
341                out << _(" or");
342             out << endl;
343             
344             if (Start == End)
345                break;
346             Start++;
347          }       
348       }     
349    }   
350 }
351                                                                         /*}}}*/
352 // ShowNew - Show packages to newly install                             /*{{{*/
353 // ---------------------------------------------------------------------
354 /* */
355 void ShowNew(ostream &out,cmdCacheFile &Cache,pkgDepCache::State *State)
356 {
357    /* Print out a list of packages that are going to be installed extra
358       to what the user asked */
359    string List;
360    string VersionsList;
361    for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
362    {
363       pkgCache::PkgIterator I(Cache,Cache.List[J]);
364       if (Cache[I].NewInstall() == true &&
365           (State == NULL || (*State)[I].NewInstall() == false)) {
366          List += string(I.Name()) + " ";
367          VersionsList += string(Cache[I].CandVersion) + "\n";
368       }
369    }
370    
371    ShowList(out,_("The following NEW packages will be installed:"),List,VersionsList);
372 }
373                                                                         /*}}}*/
374 // ShowDel - Show packages to delete                                    /*{{{*/
375 // ---------------------------------------------------------------------
376 /* */
377 void ShowDel(ostream &out,cmdCacheFile &Cache,pkgDepCache::State *State)
378 {
379    /* Print out a list of packages that are going to be removed extra
380       to what the user asked */
381    string List, RepList; // CNC:2002-07-25
382    string VersionsList;
383    for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
384    {
385       pkgCache::PkgIterator I(Cache,Cache.List[J]);
386       if (Cache[I].Delete() == true &&
387           (State == NULL || (*State)[I].Delete() == false))
388       {
389          // CNC:2002-07-25
390          bool Obsoleted = false;
391          string by;
392          for (pkgCache::DepIterator D = I.RevDependsList(); D.end() == false; D++)
393          {
394             if (D->Type == pkgCache::Dep::Obsoletes &&
395                 Cache[D.ParentPkg()].Install() &&
396                 (pkgCache::Version*)D.ParentVer() == Cache[D.ParentPkg()].InstallVer &&
397                 Cache->VS().CheckDep(I.CurrentVer().VerStr(), D) == true)
398             {
399                if (Obsoleted)
400                   by += ", " + string(D.ParentPkg().Name());
401                else
402                {
403                   Obsoleted = true;
404                   by = D.ParentPkg().Name();
405                }
406             }
407          }
408          if (Obsoleted)
409             RepList += string(I.Name()) + " (by " + by + ")  ";
410          else
411          {
412             if ((Cache[I].iFlags & pkgDepCache::Purge) == pkgDepCache::Purge)
413                List += string(I.Name()) + "* ";
414             else
415                List += string(I.Name()) + " ";
416          }
417      
418      // CNC:2004-03-09
419      VersionsList += string(I.CurrentVer().VerStr())+ "\n";
420       }
421    }
422    
423    // CNC:2002-07-25
424    ShowList(out,_("The following packages will be REPLACED:"),RepList,VersionsList);
425    ShowList(out,_("The following packages will be REMOVED:"),List,VersionsList);
426 }
427                                                                         /*}}}*/
428 // ShowKept - Show kept packages                                        /*{{{*/
429 // ---------------------------------------------------------------------
430 /* */
431 void ShowKept(ostream &out,cmdCacheFile &Cache,pkgDepCache::State *State)
432 {
433    string List;
434    string VersionsList;
435    for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
436    {     
437       pkgCache::PkgIterator I(Cache,Cache.List[J]);
438       
439       if (State == NULL) {
440          // Not interesting
441          if (Cache[I].Upgrade() == true || Cache[I].Upgradable() == false ||
442              I->CurrentVer == 0 || Cache[I].Delete() == true)
443             continue;
444       } else {
445          // Not interesting
446          if (!((Cache[I].Install() == false && (*State)[I].Install() == true) ||
447                (Cache[I].Delete() == false && (*State)[I].Delete() == true)))
448             continue;
449       }
450       
451       List += string(I.Name()) + " ";
452       VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n";
453    }
454    ShowList(out,_("The following packages have been kept back"),List,VersionsList);
455 }
456                                                                         /*}}}*/
457 // ShowUpgraded - Show upgraded packages                                /*{{{*/
458 // ---------------------------------------------------------------------
459 /* */
460 void ShowUpgraded(ostream &out,cmdCacheFile &Cache,pkgDepCache::State *State)
461 {
462    string List;
463    string VersionsList;
464    for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
465    {
466       pkgCache::PkgIterator I(Cache,Cache.List[J]);
467       
468       if (State == NULL) {
469          // Not interesting
470          if (Cache[I].Upgrade() == false || Cache[I].NewInstall() == true)
471             continue;
472       } else {
473          // Not interesting
474          if (Cache[I].NewInstall() == true ||
475              !(Cache[I].Upgrade() == true && (*State)[I].Upgrade() == false))
476             continue;
477       }
478       
479       List += string(I.Name()) + " ";
480       VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n";
481    }
482    ShowList(out,_("The following packages will be upgraded"),List,VersionsList);
483 }
484                                                                         /*}}}*/
485 // ShowDowngraded - Show downgraded packages                            /*{{{*/
486 // ---------------------------------------------------------------------
487 /* */
488 bool ShowDowngraded(ostream &out,cmdCacheFile &Cache,pkgDepCache::State *State)
489 {
490    string List;
491    string VersionsList;
492    for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
493    {
494       pkgCache::PkgIterator I(Cache,Cache.List[J]);
495       
496       if (State == NULL) {
497          // Not interesting
498          if (Cache[I].Downgrade() == false || Cache[I].NewInstall() == true)
499             continue;
500       } else {
501          // Not interesting
502          if (Cache[I].NewInstall() == true ||
503              !(Cache[I].Downgrade() == true && (*State)[I].Downgrade() == false))
504             continue;
505       }
506       
507       List += string(I.Name()) + " ";
508       VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n";
509    }
510    return ShowList(out,_("The following packages will be DOWNGRADED"),List,VersionsList);
511 }
512                                                                         /*}}}*/
513 // ShowHold - Show held but changed packages                            /*{{{*/
514 // ---------------------------------------------------------------------
515 /* */
516 bool ShowHold(ostream &out,cmdCacheFile &Cache,pkgDepCache::State *State)
517 {
518    string List;
519    string VersionsList;
520    for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
521    {
522       pkgCache::PkgIterator I(Cache,Cache.List[J]);
523       if (Cache[I].InstallVer != (pkgCache::Version *)I.CurrentVer() &&
524           I->SelectedState == pkgCache::State::Hold &&
525           (State == NULL ||
526            Cache[I].InstallVer != (*State)[I].InstallVer)) {
527          List += string(I.Name()) + " ";
528          VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n";
529       }
530    }
531
532    return ShowList(out,_("The following held packages will be changed:"),List,VersionsList);
533 }
534                                                                         /*}}}*/
535 // ShowEssential - Show an essential package warning                    /*{{{*/
536 // ---------------------------------------------------------------------
537 /* This prints out a warning message that is not to be ignored. It shows
538    all essential packages and their dependents that are to be removed. 
539    It is insanely risky to remove the dependents of an essential package! */
540 bool ShowEssential(ostream &out,cmdCacheFile &Cache,pkgDepCache::State *State)
541 {
542    string List;
543    string VersionsList;
544    bool *Added = new bool[Cache->Head().PackageCount];
545    for (unsigned int I = 0; I != Cache->Head().PackageCount; I++)
546       Added[I] = false;
547    
548    for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
549    {
550       pkgCache::PkgIterator I(Cache,Cache.List[J]);
551       if ((I->Flags & pkgCache::Flag::Essential) != pkgCache::Flag::Essential &&
552           (I->Flags & pkgCache::Flag::Important) != pkgCache::Flag::Important)
553          continue;
554       
555       // The essential package is being removed
556       if (Cache[I].Delete() == true &&
557           (State == NULL || (*State)[I].Delete() == false))
558       {
559          if (Added[I->ID] == false)
560          {
561             // CNC:2003-03-21 - Do not consider a problem if that package is being obsoleted
562             //                  by something else.
563             bool Obsoleted = false;
564             for (pkgCache::DepIterator D = I.RevDependsList(); D.end() == false; D++)
565             {
566                if (D->Type == pkgCache::Dep::Obsoletes &&
567                    Cache[D.ParentPkg()].Install() &&
568                    ((pkgCache::Version*)D.ParentVer() == Cache[D.ParentPkg()].InstallVer ||
569                     (pkgCache::Version*)D.ParentVer() == ((pkgCache::Version*)D.ParentPkg().CurrentVer())) &&
570                    Cache->VS().CheckDep(I.CurrentVer().VerStr(), D) == true)
571                {
572                   Obsoleted = true;
573                   break;
574                }
575             }
576             if (Obsoleted == false) {
577                Added[I->ID] = true;
578                List += string(I.Name()) + " ";
579             }
580         //VersionsList += string(Cache[I].CurVersion) + "\n"; ???
581          }
582       }
583       
584       if (I->CurrentVer == 0)
585          continue;
586
587       // Print out any essential package depenendents that are to be removed
588       for (pkgCache::DepIterator D = I.CurrentVer().DependsList(); D.end() == false; D++)
589       {
590          // Skip everything but depends
591          if (D->Type != pkgCache::Dep::PreDepends &&
592              D->Type != pkgCache::Dep::Depends)
593             continue;
594          
595          pkgCache::PkgIterator P = D.SmartTargetPkg();
596          if (Cache[P].Delete() == true &&
597              (State == NULL || (*State)[P].Delete() == false))
598          {
599             if (Added[P->ID] == true)
600                continue;
601
602             // CNC:2003-03-21 - Do not consider a problem if that package is being obsoleted
603             //                  by something else.
604             bool Obsoleted = false;
605             for (pkgCache::DepIterator D = P.RevDependsList(); D.end() == false; D++)
606             {
607                if (D->Type == pkgCache::Dep::Obsoletes &&
608                    Cache[D.ParentPkg()].Install() &&
609                    ((pkgCache::Version*)D.ParentVer() == Cache[D.ParentPkg()].InstallVer ||
610                     (pkgCache::Version*)D.ParentVer() == ((pkgCache::Version*)D.ParentPkg().CurrentVer())) &&
611                    Cache->VS().CheckDep(P.CurrentVer().VerStr(), D) == true)
612                {
613                   Obsoleted = true;
614                   break;
615                }
616             }
617             if (Obsoleted == true)
618                continue;
619
620             Added[P->ID] = true;
621             
622             char S[300];
623             snprintf(S,sizeof(S),_("%s (due to %s) "),P.Name(),I.Name());
624             List += S;
625         //VersionsList += "\n"; ???
626          }       
627       }      
628    }
629    
630    delete [] Added;
631    return ShowList(out,_("WARNING: The following essential packages will be removed\n"
632                          "This should NOT be done unless you know exactly what you are doing!"),List,VersionsList);
633 }
634                                                                         /*}}}*/
635 // Stats - Show some statistics                                         /*{{{*/
636 // ---------------------------------------------------------------------
637 /* */
638 void Stats(ostream &out,pkgDepCache &Dep,pkgDepCache::State *State)
639 {
640    unsigned long Upgrade = 0;
641    unsigned long Downgrade = 0;
642    unsigned long Install = 0;
643    unsigned long ReInstall = 0;
644    // CNC:2002-07-29
645    unsigned long Replace = 0;
646    unsigned long Remove = 0;
647    unsigned long Keep = 0;
648    for (pkgCache::PkgIterator I = Dep.PkgBegin(); I.end() == false; I++)
649    {
650       if (Dep[I].NewInstall() == true &&
651           (State == NULL || (*State)[I].NewInstall() == false))
652          Install++;
653       else
654       {
655          if (Dep[I].Upgrade() == true &&
656              (State == NULL || (*State)[I].Upgrade() == false))
657             Upgrade++;
658          else
659             if (Dep[I].Downgrade() == true &&
660                 (State == NULL || (*State)[I].Downgrade() == false))
661                Downgrade++;
662             else
663                if (State != NULL &&
664                    (((*State)[I].NewInstall() == true && Dep[I].NewInstall() == false) ||
665                     ((*State)[I].Upgrade() == true && Dep[I].Upgrade() == false) ||
666                     ((*State)[I].Downgrade() == true && Dep[I].Downgrade() == false)))
667                   Keep++;
668       }
669       // CNC:2002-07-29
670       if (Dep[I].Delete() == true &&
671           (State == NULL || (*State)[I].Delete() == false))
672       {
673          bool Obsoleted = false;
674          string by;
675          for (pkgCache::DepIterator D = I.RevDependsList();
676               D.end() == false; D++)
677          {
678             if (D->Type == pkgCache::Dep::Obsoletes &&
679                 Dep[D.ParentPkg()].Install() &&
680                 (pkgCache::Version*)D.ParentVer() == Dep[D.ParentPkg()].InstallVer &&
681                 Dep.VS().CheckDep(I.CurrentVer().VerStr(), D) == true)
682             {
683                Obsoleted = true;
684                break;
685             }
686          }
687          if (Obsoleted)
688             Replace++;
689          else
690             Remove++;
691       }
692       else if ((Dep[I].iFlags & pkgDepCache::ReInstall) == pkgDepCache::ReInstall &&
693                (State == NULL || !((*State)[I].iFlags & pkgDepCache::ReInstall)))
694          ReInstall++;
695    }   
696
697    ioprintf(out,_("%lu upgraded, %lu newly installed, "),
698             Upgrade,Install);
699    
700    if (ReInstall != 0)
701       ioprintf(out,_("%lu reinstalled, "),ReInstall);
702    if (Downgrade != 0)
703       ioprintf(out,_("%lu downgraded, "),Downgrade);
704    // CNC:2002-07-29
705    if (Replace != 0)
706       ioprintf(out,_("%lu replaced, "),Replace);
707
708    // CNC:2002-07-29
709    if (State == NULL)
710       ioprintf(out,_("%lu removed and %lu not upgraded.\n"),
711                Remove,Dep.KeepCount());
712    else
713       ioprintf(out,_("%lu removed and %lu kept.\n"),Remove,Keep);
714
715    
716    if (Dep.BadCount() != 0)
717       ioprintf(out,_("%lu not fully installed or removed.\n"),
718                Dep.BadCount());
719 }
720                                                                         /*}}}*/
721 bool cmdDoClean(CommandLine &CmdL)
722 {
723    if (_config->FindB("APT::Get::Simulate") == true)
724    {
725       cout << "Del " << _config->FindDir("Dir::Cache::archives") << "* " <<
726          _config->FindDir("Dir::Cache::archives") << "partial/*" << endl;
727       return true;
728    }
729
730    // Lock the archive directory
731    FileFd Lock;
732    if (_config->FindB("Debug::NoLocking",false) == false)
733    {
734       Lock.Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
735       if (_error->PendingError() == true)
736          return _error->Error(_("Unable to lock the download directory"));
737    }
738
739    pkgAcquire Fetcher;
740    Fetcher.Clean(_config->FindDir("Dir::Cache::archives"));
741    Fetcher.Clean(_config->FindDir("Dir::Cache::archives") + "partial/");
742    return true;
743 }
744
745 // FindSrc - Find a source record                                       /*{{{*/
746 // ---------------------------------------------------------------------
747 /* */
748 pkgSrcRecords::Parser *FindSrc(const char *Name,pkgRecords &Recs,
749                                pkgSrcRecords &SrcRecs,string &Src,
750                                pkgDepCache &Cache)
751 {
752    // We want to pull the version off the package specification..
753    string VerTag;
754    string TmpSrc = Name;
755    string::size_type Slash = TmpSrc.rfind('=');
756    if (Slash != string::npos)
757    {
758       VerTag = string(TmpSrc.begin() + Slash + 1,TmpSrc.end());
759       TmpSrc = string(TmpSrc.begin(),TmpSrc.begin() + Slash);
760    }
761    
762    /* Lookup the version of the package we would install if we were to
763       install a version and determine the source package name, then look
764       in the archive for a source package of the same name. In theory
765       we could stash the version string as well and match that too but
766       today there aren't multi source versions in the archive. */
767    if (_config->FindB("APT::Get::Only-Source") == false && 
768        VerTag.empty() == true)
769    {
770       pkgCache::PkgIterator Pkg = Cache.FindPkg(TmpSrc);
771       if (Pkg.end() == false)
772       {
773          pkgCache::VerIterator Ver = Cache.GetCandidateVer(Pkg);      
774          if (Ver.end() == false)
775          {
776             pkgRecords::Parser &Parse = Recs.Lookup(Ver.FileList());
777             Src = Parse.SourcePkg();
778          }
779       }   
780    }
781    
782    // No source package name..
783    if (Src.empty() == true)
784       Src = TmpSrc;
785    
786    // The best hit
787    pkgSrcRecords::Parser *Last = 0;
788    unsigned long Offset = 0;
789    string Version;
790    bool IsMatch = false;
791    
792    // If we are matching by version then we need exact matches to be happy
793    if (VerTag.empty() == false)
794       IsMatch = true;
795    
796    /* Iterate over all of the hits, which includes the resulting
797       binary packages in the search */
798    pkgSrcRecords::Parser *Parse;
799    SrcRecs.Restart();
800    while ((Parse = SrcRecs.Find(Src.c_str(),false)) != 0)
801    {
802       string Ver = Parse->Version();
803       
804       // Skip name mismatches
805       if (IsMatch == true && Parse->Package() != Src)
806          continue;
807       
808       if (VerTag.empty() == false)
809       {
810          /* Don't want to fall through because we are doing exact version 
811             matching. */
812          if (Cache.VS().CmpVersion(VerTag,Ver) != 0)
813             continue;
814          
815          Last = Parse;
816          Offset = Parse->Offset();
817          break;
818       }
819                                   
820       // Newer version or an exact match
821       if (Last == 0 || Cache.VS().CmpVersion(Version,Ver) < 0 || 
822           (Parse->Package() == Src && IsMatch == false))
823       {
824          IsMatch = Parse->Package() == Src;
825          Last = Parse;
826          Offset = Parse->Offset();
827          Version = Ver;
828       }      
829    }
830    
831    if (Last == 0)
832       return 0;
833    
834    if (Last->Jump(Offset) == false)
835       return 0;
836    
837    return Last;
838 }
839                                                                         /*}}}*/
840 // DoAutoClean - Smartly remove downloaded archives                     /*{{{*/
841 // ---------------------------------------------------------------------
842 /* This is similar to clean but it only purges things that cannot be 
843    downloaded, that is old versions of cached packages. */
844 void LogCleaner::Erase(const char *File,string Pkg,string Ver,struct stat &St) 
845 {
846       c1out << "Del " << Pkg << " " << Ver << " [" << SizeToStr(St.st_size) << "B]" << endl;
847       
848       if (_config->FindB("APT::Get::Simulate") == false)
849          unlink(File);      
850 }
851
852 // apt-cache stuff..
853
854 // LocalitySort - Sort a version list by package file locality          /*{{{*/
855 // ---------------------------------------------------------------------
856 /* */
857 int LocalityCompare(const void *a, const void *b)
858 {
859    pkgCache::VerFile *A = *(pkgCache::VerFile **)a;
860    pkgCache::VerFile *B = *(pkgCache::VerFile **)b;
861    
862    if (A == 0 && B == 0)
863       return 0;
864    if (A == 0)
865       return 1;
866    if (B == 0)
867       return -1;
868    
869    if (A->File == B->File)
870       return A->Offset - B->Offset;
871    return A->File - B->File;
872 }
873
874 void LocalitySort(pkgCache::VerFile **begin,
875                   unsigned long Count,size_t Size)
876 {   
877    qsort(begin,Count,Size,LocalityCompare);
878 }
879                                                                         /*}}}*/
880 // UnMet - Show unmet dependencies                                      /*{{{*/
881 // ---------------------------------------------------------------------
882 /* */
883 bool cmdUnMet(CommandLine &CmdL, pkgCache &Cache)
884 {
885    bool Important = _config->FindB("APT::Cache::Important",false);
886    
887    for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
888    {
889       for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; V++)
890       {
891          bool Header = false;
892          for (pkgCache::DepIterator D = V.DependsList(); D.end() == false;)
893          {
894             // Collect or groups
895             pkgCache::DepIterator Start;
896             pkgCache::DepIterator End;
897             D.GlobOr(Start,End);
898             
899             // Skip conflicts and replaces
900             if (End->Type != pkgCache::Dep::PreDepends &&
901                 End->Type != pkgCache::Dep::Depends && 
902                 End->Type != pkgCache::Dep::Suggests &&
903                 End->Type != pkgCache::Dep::Recommends)
904                continue;
905
906             // Important deps only
907             if (Important == true)
908                if (End->Type != pkgCache::Dep::PreDepends &&
909                    End->Type != pkgCache::Dep::Depends)
910                   continue;
911             
912             // Verify the or group
913             bool OK = false;
914             pkgCache::DepIterator RealStart = Start;
915             do
916             {
917                // See if this dep is Ok
918                pkgCache::Version **VList = Start.AllTargets();
919                if (*VList != 0)
920                {
921                   OK = true;
922                   delete [] VList;
923                   break;
924                }
925                delete [] VList;
926                
927                if (Start == End)
928                   break;
929                Start++;
930             }
931             while (1);
932
933             // The group is OK
934             if (OK == true)
935                continue;
936             
937             // Oops, it failed..
938             if (Header == false)
939                ioprintf(cout,_("Package %s version %s has an unmet dep:\n"),
940                         P.Name(),V.VerStr());
941             Header = true;
942             
943             // Print out the dep type
944             cout << " " << End.DepType() << ": ";
945
946             // Show the group
947             Start = RealStart;
948             do
949             {
950                cout << Start.TargetPkg().Name();
951                if (Start.TargetVer() != 0)
952                   cout << " (" << Start.CompType() << " " << Start.TargetVer() <<
953                   ")";
954                if (Start == End)
955                   break;
956                cout << " | ";
957                Start++;
958             }
959             while (1);
960             
961             cout << endl;
962          }       
963       }
964    }   
965    return true;
966 }
967                                                                         /*}}}*/
968 // DumpPackage - Show a dump of a package record                        /*{{{*/
969 // ---------------------------------------------------------------------
970 /* */
971 bool cmdDumpPackage(CommandLine &CmdL, pkgCache &Cache)
972 {   
973    for (const char **I = CmdL.FileList + 1; *I != 0; I++)
974    {
975       pkgCache::PkgIterator Pkg = Cache.FindPkg(*I);
976       if (Pkg.end() == true)
977       {
978          _error->Warning(_("Unable to locate package %s"),*I);
979          continue;
980       }
981
982       cout << "Package: " << Pkg.Name() << endl;
983       cout << "Versions: " << endl;
984       for (pkgCache::VerIterator Cur = Pkg.VersionList(); Cur.end() != true; Cur++)
985       {
986          cout << Cur.VerStr() << "." << Cur.Arch();
987          for (pkgCache::VerFileIterator Vf = Cur.FileList(); Vf.end() == false; Vf++)
988             cout << "(" << Vf.File().FileName() << ")";
989          cout << endl;
990       }
991       
992       cout << endl;
993       
994       cout << "Reverse Depends: " << endl;
995       for (pkgCache::DepIterator D = Pkg.RevDependsList(); D.end() != true; D++)
996       {
997          cout << "  " << D.ParentPkg().Name() << ',' << D.TargetPkg().Name();
998          if (D->Version != 0)
999             cout << ' ' << DeNull(D.TargetVer()) << endl;
1000          else
1001             cout << endl;
1002       }
1003       
1004       cout << "Dependencies: " << endl;
1005       for (pkgCache::VerIterator Cur = Pkg.VersionList(); Cur.end() != true; Cur++)
1006       {
1007          cout << Cur.VerStr() << " - ";
1008          for (pkgCache::DepIterator Dep = Cur.DependsList(); Dep.end() != true; Dep++)
1009             cout << Dep.TargetPkg().Name() << " (" << (int)Dep->CompareOp << " " << DeNull(Dep.TargetVer()) << ") ";
1010          cout << endl;
1011       }      
1012
1013       cout << "Provides: " << endl;
1014       for (pkgCache::VerIterator Cur = Pkg.VersionList(); Cur.end() != true; Cur++)
1015       {
1016          cout << Cur.VerStr() << " - ";
1017          for (pkgCache::PrvIterator Prv = Cur.ProvidesList(); Prv.end() != true; Prv++)
1018             cout << Prv.ParentPkg().Name() << " ";
1019          cout << endl;
1020       }
1021       cout << "Reverse Provides: " << endl;
1022       for (pkgCache::PrvIterator Prv = Pkg.ProvidesList(); Prv.end() != true; Prv++)
1023          cout << Prv.OwnerPkg().Name() << " " << Prv.OwnerVer().VerStr() << endl;            
1024    }
1025
1026    return true;
1027 }
1028                                                                         /*}}}*/
1029 // DisplayRecord - Displays the complete record for the package         /*{{{*/
1030 // ---------------------------------------------------------------------
1031 /* This displays the package record from the proper package index file. 
1032    It is not used by DumpAvail for performance reasons. */
1033 bool cmdDisplayRecord(pkgCache::VerIterator V, pkgCache &Cache)
1034 {
1035    // Find an appropriate file
1036    pkgCache::VerFileIterator Vf = V.FileList();
1037    for (; Vf.end() == false; Vf++)
1038       if ((Vf.File()->Flags & pkgCache::Flag::NotSource) == 0)
1039          break;
1040    if (Vf.end() == true)
1041       Vf = V.FileList();
1042       
1043 // CNC:2002-07-24
1044 #if HAVE_RPM
1045    pkgRecords Recs(Cache);
1046    pkgRecords::Parser &P = Recs.Lookup(Vf);
1047    const char *Start;
1048    const char *End;
1049    P.GetRec(Start,End);
1050    cout << string(Start,End-Start) << endl;
1051 #else
1052    // Check and load the package list file
1053    pkgCache::PkgFileIterator I = Vf.File();
1054    if (I.IsOk() == false)
1055       return _error->Error(_("Package file %s is out of sync."),I.FileName());
1056    
1057    FileFd PkgF(I.FileName(),FileFd::ReadOnly);
1058    if (_error->PendingError() == true)
1059       return false;
1060    
1061    // Read the record and then write it out again.
1062    unsigned char *Buffer = new unsigned char[Cache->HeaderP->MaxVerFileSize+1];
1063    Buffer[V.FileList()->Size] = '\n';
1064    if (PkgF.Seek(V.FileList()->Offset) == false ||
1065        PkgF.Read(Buffer,V.FileList()->Size) == false ||
1066        fwrite(Buffer,1,V.FileList()->Size+1,stdout) < V.FileList()->Size+1)
1067    {
1068       delete [] Buffer;
1069       return false;
1070    }
1071    
1072    delete [] Buffer;
1073 #endif
1074
1075    return true;
1076 }
1077
1078 // Depends - Print out a dependency tree                                /*{{{*/
1079 // ---------------------------------------------------------------------
1080 /* */
1081 bool cmdDepends(CommandLine &CmdL, pkgCache &Cache)
1082 {
1083    SPtrArray<unsigned> Colours = new unsigned[Cache.Head().PackageCount];
1084    memset(Colours,0,sizeof(*Colours)*Cache.Head().PackageCount);
1085    
1086    for (const char **I = CmdL.FileList + 1; *I != 0; I++)
1087    {
1088       pkgCache::PkgIterator Pkg = Cache.FindPkg(*I);
1089       if (Pkg.end() == true)
1090       {
1091          _error->Warning(_("Unable to locate package %s"),*I);
1092          continue;
1093       }
1094       Colours[Pkg->ID] = 1;
1095    }
1096    
1097    bool Recurse = _config->FindB("APT::Cache::RecurseDepends",false);
1098    bool Installed = _config->FindB("APT::Cache::Installed",false);
1099    bool DidSomething;
1100    do
1101    {
1102       DidSomething = false;
1103       for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++)
1104       {
1105          if (Colours[Pkg->ID] != 1)
1106             continue;
1107          Colours[Pkg->ID] = 2;
1108          DidSomething = true;
1109          
1110          pkgCache::VerIterator Ver = Pkg.VersionList();
1111          if (Ver.end() == true)
1112          {
1113             cout << '<' << Pkg.Name() << '>' << endl;
1114             continue;
1115          }
1116          
1117          // CNC:2003-03-03
1118          cout << Pkg.Name() << "-" << Ver.VerStr() << endl;
1119          
1120          for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; D++)
1121          {
1122
1123             pkgCache::PkgIterator Trg = D.TargetPkg();
1124
1125             if((Installed && Trg->CurrentVer != 0) || !Installed)
1126               {
1127
1128                 if ((D->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or)
1129                   cout << " |";
1130                 else
1131                   cout << "  ";
1132             
1133                 // Show the package
1134                 if (Trg->VersionList == 0)
1135                    cout << D.DepType() << ": <" << Trg.Name() << ">" << endl;
1136                 // CNC:2003-03-03
1137                 else if (D.TargetVer() == 0)
1138                    cout << D.DepType() << ": " << Trg.Name() << endl;
1139                 else
1140                    cout << D.DepType() << ": " << Trg.Name()
1141                         << " " << D.CompType() << " " << D.TargetVer() << endl;
1142             
1143                 if (Recurse == true)
1144                   Colours[D.TargetPkg()->ID]++;
1145
1146               }
1147             
1148             // Display all solutions
1149             SPtrArray<pkgCache::Version *> List = D.AllTargets();
1150             pkgPrioSortList(Cache,List);
1151             for (pkgCache::Version **I = List; *I != 0; I++)
1152             {
1153                pkgCache::VerIterator V(Cache,*I);
1154                if (V != Cache.VerP + V.ParentPkg()->VersionList ||
1155                    V->ParentPkg == D->Package)
1156                   continue;
1157                // CNC:2003-03-03
1158                cout << "    " << V.ParentPkg().Name()
1159                     << "-" << V.VerStr() << endl;
1160                
1161                if (Recurse == true)
1162                   Colours[D.ParentPkg()->ID]++;
1163             }
1164          }
1165       }      
1166    }   
1167    while (DidSomething == true);
1168    
1169    return true;
1170 }
1171
1172 // RDepends - Print out a reverse dependency tree - mbc                 /*{{{*/
1173 // ---------------------------------------------------------------------
1174 /* */
1175 bool cmdRDepends(CommandLine &CmdL, pkgCache &Cache)
1176 {
1177    SPtrArray<unsigned> Colours = new unsigned[Cache.Head().PackageCount];
1178    memset(Colours,0,sizeof(*Colours)*Cache.Head().PackageCount);
1179    
1180    for (const char **I = CmdL.FileList + 1; *I != 0; I++)
1181    {
1182       pkgCache::PkgIterator Pkg = Cache.FindPkg(*I);
1183       if (Pkg.end() == true)
1184       {
1185          _error->Warning(_("Unable to locate package %s"),*I);
1186          continue;
1187       }
1188       Colours[Pkg->ID] = 1;
1189    }
1190    
1191    bool Recurse = _config->FindB("APT::Cache::RecurseDepends",false);
1192    bool Installed = _config->FindB("APT::Cache::Installed",false);
1193    bool DidSomething;
1194    do
1195    {
1196       DidSomething = false;
1197       for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++)
1198       {
1199          if (Colours[Pkg->ID] != 1)
1200             continue;
1201          Colours[Pkg->ID] = 2;
1202          DidSomething = true;
1203          
1204          pkgCache::VerIterator Ver = Pkg.VersionList();
1205          if (Ver.end() == true)
1206          {
1207             cout << '<' << Pkg.Name() << '>' << endl;
1208             continue;
1209          }
1210          
1211          cout << Pkg.Name() << endl;
1212          
1213          cout << "Reverse Depends:" << endl;
1214          for (pkgCache::DepIterator D = Pkg.RevDependsList(); D.end() == false; D++)
1215          {          
1216             // Show the package
1217             pkgCache::PkgIterator Trg = D.ParentPkg();
1218
1219             if((Installed && Trg->CurrentVer != 0) || !Installed)
1220               {
1221
1222                 if ((D->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or)
1223                   cout << " |";
1224                 else
1225                   cout << "  ";
1226
1227                 if (Trg->VersionList == 0)
1228                   cout << D.DepType() << ": <" << Trg.Name() << ">" << endl;
1229                 else
1230                   cout << Trg.Name() << endl;
1231
1232                 if (Recurse == true)
1233                   Colours[D.ParentPkg()->ID]++;
1234
1235               }
1236             
1237             // Display all solutions
1238             SPtrArray<pkgCache::Version *> List = D.AllTargets();
1239             pkgPrioSortList(Cache,List);
1240             for (pkgCache::Version **I = List; *I != 0; I++)
1241             {
1242                pkgCache::VerIterator V(Cache,*I);
1243                if (V != Cache.VerP + V.ParentPkg()->VersionList ||
1244                    V->ParentPkg == D->Package)
1245                   continue;
1246                cout << "    " << V.ParentPkg().Name() << endl;
1247                
1248                if (Recurse == true)
1249                   Colours[D.ParentPkg()->ID]++;
1250             }
1251          }
1252       }      
1253    }   
1254    while (DidSomething == true);
1255    
1256    return true;
1257 }
1258
1259                                                                         /*}}}*/
1260 // CNC:2003-02-19
1261 // WhatDepends - Print out a reverse dependency tree                    /*{{{*/
1262 // ---------------------------------------------------------------------
1263 /* */
1264 bool cmdWhatDepends(CommandLine &CmdL, pkgCache &Cache)
1265 {
1266    SPtrArray<unsigned> Colours = new unsigned[Cache.Head().PackageCount];
1267    memset(Colours,0,sizeof(*Colours)*Cache.Head().PackageCount);
1268    
1269    for (const char **I = CmdL.FileList + 1; *I != 0; I++)
1270    {
1271       pkgCache::PkgIterator Pkg = Cache.FindPkg(*I);
1272       if (Pkg.end() == true)
1273       {
1274          _error->Warning(_("Unable to locate package %s"),*I);
1275          continue;
1276       }
1277       Colours[Pkg->ID] = 1;
1278    }
1279    
1280    bool Recurse = _config->FindB("APT::Cache::RecurseDepends",false);
1281    bool DidSomething;
1282    do
1283    {
1284       DidSomething = false;
1285       for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++)
1286       {
1287          if (Colours[Pkg->ID] != 1)
1288             continue;
1289          Colours[Pkg->ID] = 2;
1290          DidSomething = true;
1291          
1292          pkgCache::VerIterator Ver = Pkg.VersionList();
1293          if (Ver.end() == true)
1294             cout << '<' << Pkg.Name() << '>' << endl;
1295          else
1296             cout << Pkg.Name() << "-" << Ver.VerStr() << endl;
1297
1298          SPtrArray<unsigned> LocalColours = 
1299                      new unsigned[Cache.Head().PackageCount];
1300          memset(LocalColours,0,sizeof(*LocalColours)*Cache.Head().PackageCount);
1301             
1302          // Display all dependencies directly on the package.
1303          for (pkgCache::DepIterator RD = Pkg.RevDependsList();
1304               RD.end() == false; RD++)
1305          {
1306             pkgCache::PkgIterator Parent = RD.ParentPkg();
1307
1308             if (LocalColours[Parent->ID] == 1)
1309                continue;
1310             LocalColours[Parent->ID] = 1;
1311                
1312             if (Ver.end() == false && RD.TargetVer() &&
1313                 Cache.VS->CheckDep(Ver.VerStr(),RD) == false)
1314                continue;
1315
1316             if (Recurse == true && Colours[Parent->ID] == 0)
1317                Colours[Parent->ID] = 1;
1318
1319             pkgCache::VerIterator ParentVer = Parent.VersionList();
1320
1321             // Show the package
1322             cout << "  " << Parent.Name()
1323                  << "-" << ParentVer.VerStr() << endl;
1324
1325             // Display all dependencies from that package that relate
1326             // to the queried package.
1327             for (pkgCache::DepIterator D = ParentVer.DependsList();
1328                  D.end() == false; D++)
1329             {
1330                // If this is a virtual package, there's no provides.
1331                if (Ver.end() == true) {
1332                   // If it's not the same package, and there's no provides
1333                   // skip that package.
1334                   if (D.TargetPkg() != Pkg)
1335                      continue;
1336                } else if (D.TargetPkg() != Pkg ||
1337                           Cache.VS->CheckDep(Ver.VerStr(),D) == false) {
1338                   // Oops. Either it's not the same package, or the
1339                   // version didn't match. Check virtual provides from
1340                   // the queried package version and verify if this
1341                   // dependency matches one of those.
1342                   bool Hit = false;
1343                   for (pkgCache::PrvIterator Prv = Ver.ProvidesList();
1344                        Prv.end() == false; Prv++) {
1345                      if (Prv.ParentPkg() == D.TargetPkg() &&
1346                          (Prv.ParentPkg()->VersionList == 0 ||
1347                           Cache.VS->CheckDep(Prv.ProvideVersion(),D)==false)) {
1348                         Hit = true;
1349                         break;
1350                      }
1351                   }
1352                   if (Hit == false)
1353                      continue;
1354                }
1355
1356                // Bingo!
1357                pkgCache::PkgIterator Trg = D.TargetPkg();
1358                if (Trg->VersionList == 0)
1359                   cout << "    " << D.DepType()
1360                                  << ": <" << Trg.Name() << ">" << endl;
1361                else if (D.TargetVer() == 0)
1362                   cout << "    " << D.DepType()
1363                                  << ": " << Trg.Name() << endl;
1364                else
1365                   cout << "    " << D.DepType()
1366                                  << ": " << Trg.Name()
1367                                  << " " << D.CompType() << " "
1368                                  << D.TargetVer() << endl;
1369
1370                // Display all solutions
1371                SPtrArray<pkgCache::Version *> List = D.AllTargets();
1372                pkgPrioSortList(Cache,List);
1373                for (pkgCache::Version **I = List; *I != 0; I++)
1374                {
1375                   pkgCache::VerIterator V(Cache,*I);
1376                   if (V != Cache.VerP + V.ParentPkg()->VersionList ||
1377                       V->ParentPkg == D->Package)
1378                      continue;
1379                   cout << "      " << V.ParentPkg().Name()
1380                        << "-" << V.VerStr() << endl;
1381                   
1382                   if (Recurse == true)
1383                      Colours[D.ParentPkg()->ID]++;
1384                }
1385             }
1386          }
1387
1388          // Is this a virtual package the user queried directly?
1389          if (Ver.end())
1390             continue;
1391
1392          // Display all dependencies on virtual provides, which were not
1393          // yet shown in the step above.
1394          for (pkgCache::PrvIterator RDPrv = Ver.ProvidesList();
1395               RDPrv.end() == false; RDPrv++) {
1396             for (pkgCache::DepIterator RD = RDPrv.ParentPkg().RevDependsList();
1397                  RD.end() == false; RD++)
1398             {
1399                pkgCache::PkgIterator Parent = RD.ParentPkg();
1400
1401                if (LocalColours[Parent->ID] == 1)
1402                   continue;
1403                LocalColours[Parent->ID] = 1;
1404                   
1405                if (Ver.end() == false &&
1406                    Cache.VS->CheckDep(Ver.VerStr(),RD) == false)
1407                   continue;
1408
1409                if (Recurse == true && Colours[Parent->ID] == 0)
1410                   Colours[Parent->ID] = 1;
1411
1412                pkgCache::VerIterator ParentVer = Parent.VersionList();
1413
1414                // Show the package
1415                cout << "  " << Parent.Name()
1416                     << "-" << ParentVer.VerStr() << endl;
1417
1418                for (pkgCache::DepIterator D = ParentVer.DependsList();
1419                     D.end() == false; D++)
1420                {
1421                   // Go on if it's the same package and version or
1422                   // if it's the same package and has no versions
1423                   // (a virtual package).
1424                   if (D.TargetPkg() != RDPrv.ParentPkg() ||
1425                       (RDPrv.ProvideVersion() != 0 &&
1426                        Cache.VS->CheckDep(RDPrv.ProvideVersion(),D) == false))
1427                      continue;
1428
1429                   // Bingo!
1430                   pkgCache::PkgIterator Trg = D.TargetPkg();
1431                   if (Trg->VersionList == 0)
1432                      cout << "    " << D.DepType()
1433                                     << ": <" << Trg.Name() << ">" << endl;
1434                   else if (D.TargetVer() == 0)
1435                      cout << "    " << D.DepType()
1436                                     << ": " << Trg.Name() << endl;
1437                   else
1438                      cout << "    " << D.DepType()
1439                                     << ": " << Trg.Name()
1440                                     << " " << D.CompType() << " "
1441                                     << D.TargetVer() << endl;
1442
1443                   // Display all solutions
1444                   SPtrArray<pkgCache::Version *> List = D.AllTargets();
1445                   pkgPrioSortList(Cache,List);
1446                   for (pkgCache::Version **I = List; *I != 0; I++)
1447                   {
1448                      pkgCache::VerIterator V(Cache,*I);
1449                      if (V != Cache.VerP + V.ParentPkg()->VersionList ||
1450                          V->ParentPkg == D->Package)
1451                         continue;
1452                      cout << "      " << V.ParentPkg().Name()
1453                           << "-" << V.VerStr() << endl;
1454                      
1455                      if (Recurse == true)
1456                         Colours[D.ParentPkg()->ID]++;
1457                   }
1458                }
1459             }
1460          }
1461       } 
1462    }
1463    while (DidSomething == true);
1464    
1465    return true;
1466 }
1467                                                                         /*}}}*/
1468
1469 // WhatProvides - Show all packages that provide the given (virtual) package
1470 // ---------------------------------------------------------------------
1471 /* */
1472 bool cmdWhatProvides(CommandLine &CmdL, pkgCache &Cache)
1473 {
1474   bool    found;
1475
1476   for (const char **I = CmdL.FileList + 1; *I != 0; I++)
1477   {
1478        cout << "<" << *I << ">" << endl;
1479        found = false;
1480        for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++)
1481        {
1482             for (pkgCache::VerIterator Ver = Pkg.VersionList(); !Ver.end(); Ver++)
1483             {
1484                  if (!strcmp(Pkg.Name(), *I))
1485                  {
1486                       // match on real package, ignore any provides in the package
1487                       // since they would be meaningless
1488                       cout << "  " << Pkg.Name() << "-" << Ver.VerStr() << endl;
1489                       found = true;
1490                  }
1491                  else
1492                  {
1493                       // seach in package's provides list
1494                       for (pkgCache::PrvIterator Prv = Ver.ProvidesList(); Prv.end() == false; Prv++)
1495                       {
1496                            if (!strcmp(Prv.Name(), *I))
1497                            {
1498                                 cout << "  " << Pkg.Name() << "-" << Ver.VerStr() << endl;
1499                                 cout << "    Provides: <" << Prv.Name();
1500                                 if (Prv.ProvideVersion() != 0)
1501                                         cout << " = " << Prv.ProvideVersion();
1502                                 cout << ">" << endl;
1503                                 found = true;
1504                            }
1505                       }
1506                  }
1507             }
1508        }
1509        
1510        if (!found)
1511             cout << "  nothing provides <" << *I << ">" << endl;
1512   }
1513   
1514   return true;
1515 }
1516
1517 bool cmdDoList(CommandLine &CmdL, cmdCacheFile &Cache)
1518 {
1519    bool MatchAll = (CmdL.FileSize() == 1);
1520    bool ShowUpgradable = _config->FindB("APT::Cache::ShowUpgradable", false);
1521    bool ShowInstalled = _config->FindB("APT::Cache::ShowInstalled", false);
1522
1523    const char **PatternList = &CmdL.FileList[1];
1524    int NumPatterns = CmdL.FileSize()-1;
1525
1526    bool ShowVersion = _config->FindB("APT::Cache::ShowVersion", false);
1527    bool ShowSummary = _config->FindB("APT::Cache::ShowSummary", false);
1528
1529    const char *PkgName;
1530    vector<int> Matches(Cache->Head().PackageCount);
1531    size_t NumMatches = 0;
1532    size_t Len = 0, NameMaxLen = 0, VerMaxLen = 0;
1533    bool Matched;
1534    for (unsigned int J = 0; J < Cache->Head().PackageCount; J++)
1535    {
1536       Matched = false;
1537       pkgCache::PkgIterator Pkg(Cache,Cache.List[J]);
1538       if (Pkg->VersionList == 0)
1539          continue;
1540       if (ShowInstalled && Pkg->CurrentVer == 0)
1541          continue;
1542       if (ShowUpgradable &&
1543           (Pkg->CurrentVer == 0 || Cache[Pkg].Upgradable() == false))
1544          continue;
1545       PkgName = Pkg.Name();
1546       if (MatchAll == true)
1547          Matched = true;
1548       else for (int i=0; i != NumPatterns; i++) {
1549          if (fnmatch(PatternList[i], PkgName, 0) == 0) {
1550             Matched = true;
1551             break;
1552          }
1553       }
1554       if (Matched == true) {
1555          Matches[NumMatches++] = J;
1556          Len = strlen(PkgName);
1557          if (Len > NameMaxLen)
1558             NameMaxLen = Len;
1559          if (ShowVersion == true && Pkg->CurrentVer != 0) {
1560             Len = strlen(Pkg.CurrentVer().VerStr());
1561             if (Len > VerMaxLen)
1562                VerMaxLen = Len;
1563          }
1564       }
1565    }
1566
1567    if (NumMatches == 0)
1568       return true;
1569
1570    if (ShowVersion == true) {
1571       const char *NameLabel = _("Name");
1572       const char *InstalledLabel = _("Installed");
1573       const char *CandidateLabel = _("Candidate");
1574       size_t NameLen = strlen(NameLabel);
1575       size_t InstalledLen = strlen(InstalledLabel);
1576       size_t CandidateLen = strlen(CandidateLabel);
1577
1578       unsigned int FirstColumn = NameMaxLen+2;
1579       if (FirstColumn < NameLen+2)
1580          FirstColumn = NameLen+2;
1581
1582       unsigned int SecondColumn = VerMaxLen+2;
1583       if (SecondColumn < InstalledLen+2)
1584          SecondColumn = InstalledLen+2;
1585
1586       vector<char> BlankFirst(FirstColumn+1,' ');
1587       BlankFirst[FirstColumn] = 0;
1588
1589       vector<char> BlankSecond(SecondColumn+1,' ');
1590       BlankSecond[SecondColumn] = 0;
1591
1592       vector<char> Bar(ScreenWidth+1,'-');
1593       Bar[ScreenWidth] = 0;
1594
1595       c2out << NameLabel << &BlankFirst[NameLen]
1596             << InstalledLabel << &BlankSecond[InstalledLen]
1597             << CandidateLabel << endl;
1598       c2out << &Bar[ScreenWidth-NameLen] << &BlankFirst[NameLen]
1599             << &Bar[ScreenWidth-InstalledLen] << &BlankSecond[InstalledLen]
1600             << &Bar[ScreenWidth-CandidateLen] << endl;
1601
1602       const char *Str;
1603       size_t StrLen;
1604       for (unsigned int K = 0; K != NumMatches; K++) {
1605          pkgCache::PkgIterator Pkg(Cache,Cache.List[Matches[K]]);
1606          Str = Pkg.Name();
1607          StrLen = strlen(Str);
1608          c2out << Str << &BlankFirst[StrLen];
1609          if (Pkg->CurrentVer != 0) {
1610             Str = Pkg.CurrentVer().VerStr();
1611             StrLen = strlen(Str);
1612             if (Len < SecondColumn-1)
1613                c2out << Str << &BlankSecond[StrLen];
1614             else
1615                c2out << Str << " ";
1616          } else {
1617             c2out << "-" << &BlankSecond[1];
1618          }
1619          Str = "-";
1620          if (Cache[Pkg].CandidateVer != 0) {
1621             Str = Cache[Pkg].CandidateVerIter(Cache).VerStr();
1622             if (Pkg->CurrentVer != 0 &&
1623                 strcmp(Str, Pkg.CurrentVer().VerStr()) == 0)
1624                Str = "-";
1625          }
1626          c2out << Str << endl;
1627       }
1628    } else if (ShowSummary == true) {
1629       pkgRecords Recs(Cache);
1630       if (_error->PendingError() == true)
1631          return false;
1632       for (unsigned int K = 0; K != NumMatches; K++) {
1633          pkgCache::PkgIterator Pkg(Cache,Cache.List[Matches[K]]);
1634          pkgRecords::Parser &Parse = Recs.Lookup(Pkg.VersionList().FileList());
1635          c2out << Pkg.Name() << " - " << Parse.ShortDesc() << endl;
1636       }
1637    } else {
1638       unsigned int PerLine = ScreenWidth/(NameMaxLen+2);
1639       if (PerLine == 0) PerLine = 1;
1640       unsigned int ColumnLen = ScreenWidth/PerLine;
1641       unsigned int NumLines = (NumMatches+PerLine-1)/PerLine;
1642       vector<char> Blank(ColumnLen+1,' ');
1643       Blank[ColumnLen] = 0;
1644
1645       const char *Str;
1646       size_t StrLen;
1647       unsigned int K;
1648       for (unsigned int Line = 0; Line != NumLines; Line++) {
1649          for (unsigned int Entry = 0; Entry != PerLine; Entry++) {
1650             K = Line+(Entry*NumLines);
1651             if (K >= NumMatches)
1652                break;
1653             pkgCache::PkgIterator Pkg(Cache,Cache.List[Matches[K]]);
1654             Str = Pkg.Name();
1655             StrLen = strlen(Str);
1656             if (Len < ColumnLen-1)
1657                c2out << Str << &Blank[StrLen];
1658             else
1659                c2out << Str << " ";
1660          }
1661          c2out << endl;
1662       }
1663    }
1664    
1665    return true;
1666 }
1667
1668 struct ExVerFile
1669 {
1670    pkgCache::VerFile *Vf;
1671    bool NameMatch;
1672 };
1673
1674 bool cmdSearch(CommandLine &CmdL, pkgCache &Cache)
1675 {
1676    bool ShowFull = _config->FindB("APT::Cache::ShowFull",false);
1677    bool NamesOnly = _config->FindB("APT::Cache::NamesOnly",false);
1678    unsigned NumPatterns = CmdL.FileSize() -1;
1679    
1680    pkgDepCache::Policy Plcy;
1681    
1682    // Make sure there is at least one argument
1683    if (NumPatterns < 1)
1684       return _error->Error(_("You must give exactly one pattern"));
1685    
1686    // Compile the regex pattern
1687    regex_t *Patterns = new regex_t[NumPatterns];
1688    memset(Patterns,0,sizeof(*Patterns)*NumPatterns);
1689    for (unsigned I = 0; I != NumPatterns; I++)
1690    {
1691       if (regcomp(&Patterns[I],CmdL.FileList[I+1],REG_EXTENDED | REG_ICASE | 
1692                   REG_NOSUB) != 0)
1693       {
1694          for (; I != 0; I--)
1695             regfree(&Patterns[I]);
1696          return _error->Error("Regex compilation error");
1697       }      
1698    }
1699    
1700    // Create the text record parser
1701    pkgRecords Recs(Cache);
1702    if (_error->PendingError() == true)
1703    {
1704       for (unsigned I = 0; I != NumPatterns; I++)
1705          regfree(&Patterns[I]);
1706       return false;
1707    }
1708    
1709    ExVerFile *VFList = new ExVerFile[Cache.HeaderP->PackageCount+1];
1710    memset(VFList,0,sizeof(*VFList)*Cache.HeaderP->PackageCount+1);
1711
1712    // Map versions that we want to write out onto the VerList array.
1713    for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
1714    {
1715       VFList[P->ID].NameMatch = NumPatterns != 0;
1716       for (unsigned I = 0; I != NumPatterns; I++)
1717       {
1718          if (regexec(&Patterns[I],P.Name(),0,0,0) == 0)
1719             VFList[P->ID].NameMatch &= true;
1720          else
1721             VFList[P->ID].NameMatch = false;
1722       }
1723         
1724       // Doing names only, drop any that dont match..
1725       if (NamesOnly == true && VFList[P->ID].NameMatch == false)
1726          continue;
1727          
1728       // Find the proper version to use. 
1729       pkgCache::VerIterator V = Plcy.GetCandidateVer(P);
1730       if (V.end() == false)
1731          VFList[P->ID].Vf = V.FileList();
1732    }
1733       
1734    // Include all the packages that provide matching names too
1735    for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
1736    {
1737       if (VFList[P->ID].NameMatch == false)
1738          continue;
1739
1740       for (pkgCache::PrvIterator Prv = P.ProvidesList() ; Prv.end() == false; Prv++)
1741       {
1742          pkgCache::VerIterator V = Plcy.GetCandidateVer(Prv.OwnerPkg());
1743          if (V.end() == false)
1744          {
1745             VFList[Prv.OwnerPkg()->ID].Vf = V.FileList();
1746             VFList[Prv.OwnerPkg()->ID].NameMatch = true;
1747          }
1748       }
1749    }
1750
1751    LocalitySort(&VFList->Vf,Cache.HeaderP->PackageCount,sizeof(*VFList));
1752
1753    // Iterate over all the version records and check them
1754    for (ExVerFile *J = VFList; J->Vf != 0; J++)
1755    {
1756       pkgRecords::Parser &P = Recs.Lookup(pkgCache::VerFileIterator(Cache,J->Vf));
1757
1758       bool Match = true;
1759       if (J->NameMatch == false)
1760       {
1761          string LongDesc = P.LongDesc(); 
1762          // CNC 2004-04-10
1763          string ShortDesc = P.ShortDesc();
1764          Match = NumPatterns != 0;
1765          for (unsigned I = 0; I != NumPatterns; I++)
1766          {
1767             if (regexec(&Patterns[I],LongDesc.c_str(),0,0,0) == 0 ||
1768                 regexec(&Patterns[I],ShortDesc.c_str(),0,0,0) == 0)
1769                Match &= true;
1770             else
1771                Match = false;
1772          }
1773       }
1774       
1775       if (Match == true)
1776       {
1777          if (ShowFull == true)
1778          {
1779             const char *Start;
1780             const char *End;
1781             P.GetRec(Start,End);
1782             cout << string(Start,End-Start) << endl;
1783          }       
1784          else
1785             cout << P.Name() << " - " << P.ShortDesc() << endl;
1786       }
1787    }
1788    
1789    delete [] VFList;
1790    for (unsigned I = 0; I != NumPatterns; I++)
1791       regfree(&Patterns[I]);
1792    if (ferror(stdout))
1793        return _error->Error("Write to stdout failed");
1794    return true;
1795 }
1796                                                                         /*}}}*/
1797 bool cmdSearchFile(CommandLine &CmdL, pkgCache &Cache)
1798 {
1799    pkgRecords Recs(Cache);
1800    pkgDepCache::Policy Plcy;
1801
1802    for (const char **I = CmdL.FileList + 1; *I != 0; I++) {
1803       pkgCache::PkgIterator Pkg = Cache.PkgBegin();
1804       for (; Pkg.end() == false; Pkg++) {
1805          if (_config->FindB("APT::Cache::AllVersions", false) == true) {
1806             pkgCache::VerIterator Ver = Pkg.VersionList();
1807             for (; Ver.end() == false; Ver++) {
1808                pkgRecords::Parser &Parse = Recs.Lookup(Ver.FileList());
1809                if (Parse.HasFile(*I)) {
1810                   cout << *I << " " << Pkg.Name() << "-" << Ver.VerStr() << endl;
1811                }
1812             }
1813          } else {
1814             pkgCache::VerIterator Ver = Plcy.GetCandidateVer(Pkg);
1815             if (Ver.end() == false) {
1816                pkgRecords::Parser &Parse = Recs.Lookup(Ver.FileList());
1817                if (Parse.HasFile(*I)) {
1818                   cout << *I << " " << Pkg.Name() << "-" << Ver.VerStr() << endl;
1819                }
1820             }
1821          }
1822       }
1823    }
1824
1825    return true;
1826 }
1827
1828 bool matchPackages(CommandLine &CmdL, pkgCache &Cache, 
1829                    vector<pkgCache::Version *> &PkgVersions,
1830                    bool AllVersions=false)
1831 {
1832    pkgDepCache::Policy Plcy;
1833    for (const char **I = CmdL.FileList + 1; *I != 0; I++) {
1834       // TODO: support globbing/regexp + various typical name.arch,
1835       // name-ver[-rel] etc cases here..
1836       pkgCache::PkgIterator Pkg = Cache.FindPkg(*I);
1837       if (Pkg.end() == true)
1838       {
1839          _error->Warning(_("Unable to locate package %s"),*I);
1840          continue;
1841       }
1842
1843       // If it's a virtual package, require user to select similarly to apt-get
1844       if (Pkg.VersionList().end() == true and Pkg->ProvidesList != 0) {
1845          ioprintf(cout, _("Package %s is a virtual package provided by:\n"),
1846                   Pkg.Name());
1847          pkgCache::PrvIterator Prv = Pkg.ProvidesList();
1848          for (; Prv.end() == false; Prv++) {
1849             pkgCache::VerIterator V = Plcy.GetCandidateVer(Prv.OwnerPkg());
1850             if (V.end() == true)
1851                continue;
1852             if (V != Prv.OwnerVer())
1853                continue;
1854             cout << "  " << Prv.OwnerPkg().Name() << " " << V.VerStr() << endl;
1855          }
1856          cout << _("You should explicitly select one to show.") << endl;
1857          _error->Error(_("Package %s is a virtual package with multiple providers."), Pkg.Name());
1858          continue;
1859       }
1860
1861       pkgCache::VerIterator Ver;
1862       if (AllVersions == true) {
1863          Ver = Pkg.VersionList();
1864          for (; Ver.end() == false; Ver++) {
1865             PkgVersions.push_back(&(*Ver));
1866          }
1867       } else {
1868          Ver = Plcy.GetCandidateVer(Pkg);
1869          if (Ver.end() == true || Ver.FileList().end() == true)
1870             continue;
1871          PkgVersions.push_back(&(*Ver));
1872       }
1873    }
1874    return true;
1875 }        
1876
1877 bool cmdFileList(CommandLine &CmdL, pkgCache &Cache)
1878 {
1879    vector<pkgCache::Version *> PkgVersions;
1880    matchPackages(CmdL, Cache, PkgVersions, 
1881                  _config->FindB("APT::Cache::AllVersions", false));
1882
1883    pkgRecords Recs(Cache);
1884
1885    vector<pkgCache::Version *>::iterator Ver = PkgVersions.begin();
1886    for (; Ver != PkgVersions.end(); Ver++) {
1887       pkgCache::VerIterator V(Cache, (*Ver));
1888       pkgRecords::Parser &Parse = Recs.Lookup(V.FileList());
1889       vector<string> Files;
1890       Parse.FileList(Files);
1891       vector<string>::iterator F = Files.begin();
1892       for (; F != Files.end(); F++) {
1893             cout << (*F) << endl;
1894       }
1895    }
1896
1897    return true;
1898 }
1899
1900 bool cmdShowPackage(CommandLine &CmdL, pkgCache &Cache)
1901 {   
1902    vector<pkgCache::Version *> PkgVersions;
1903    matchPackages(CmdL, Cache, PkgVersions, 
1904                  _config->FindB("APT::Cache::AllVersions", false));
1905
1906    vector<pkgCache::Version *>::iterator Ver = PkgVersions.begin();
1907    for (; Ver != PkgVersions.end(); Ver++) {
1908       pkgCache::VerIterator V(Cache, (*Ver));
1909    
1910       if (cmdDisplayRecord(V, Cache) == false)
1911          return false;
1912       }
1913
1914    if (PkgVersions.size() > 0)
1915         return true;
1916    return _error->Error(_("No packages found"));
1917 }
1918
1919 bool cmdChangeLog(CommandLine &CmdL, pkgCache &Cache)
1920 {
1921    vector<pkgCache::Version *> PkgVersions;
1922    matchPackages(CmdL, Cache, PkgVersions, 
1923                  _config->FindB("APT::Cache::AllVersions", false));
1924
1925    pkgRecords Recs(Cache);
1926
1927    vector<pkgCache::Version *>::iterator Ver = PkgVersions.begin();
1928    for (; Ver != PkgVersions.end(); Ver++) {
1929       pkgCache::VerIterator V(Cache, (*Ver));
1930       pkgRecords::Parser &Parse = Recs.Lookup(V.FileList());
1931
1932       vector<ChangeLogEntry *> ChangeLog;
1933       if (Parse.ChangeLog(ChangeLog) == false) {
1934          _error->Warning(_("Changelog data not available for the repository."));
1935          return true;
1936       }
1937       cout << V.ParentPkg().Name() << "-" << V.VerStr() << ":" << endl;
1938
1939       tm *ptm;
1940       char buf[256];
1941       vector<ChangeLogEntry *>::iterator F = ChangeLog.begin();
1942       for (; F != ChangeLog.end(); F++) {
1943          ptm = localtime(&(*F)->Time);
1944          strftime(buf, sizeof(buf), "%a %b %d %Y", ptm);
1945          cout << "* " << buf << " " << (*F)->Author << endl;
1946          cout << (*F)->Text << endl << endl;
1947       }
1948    }
1949    return true;
1950 }
1951
1952 // vim:sts=3:sw=3