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