- initial import of revision 374 from cnc
[apt.git] / cmdline / apt-cache.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description                                                          /*{{{*/
3 // $Id: apt-cache.cc,v 1.67 2003/08/02 19:53:23 mdz Exp $
4 /* ######################################################################
5    
6    apt-cache - Manages the cache files
7    
8    apt-cache provides some functions fo manipulating the cache files.
9    It uses the command line interface common to all the APT tools. 
10    
11    Returns 100 on failure, 0 on success.
12    
13    ##################################################################### */
14                                                                         /*}}}*/
15 // Include Files                                                        /*{{{*/
16 #include <apt-pkg/error.h>
17 #include <apt-pkg/pkgcachegen.h>
18 #include <apt-pkg/init.h>
19 #include <apt-pkg/progress.h>
20 #include <apt-pkg/sourcelist.h>
21 #include <apt-pkg/cmndline.h>
22 #include <apt-pkg/strutl.h>
23 #include <apt-pkg/pkgrecords.h>
24 #include <apt-pkg/srcrecords.h>
25 #include <apt-pkg/version.h>
26 #include <apt-pkg/policy.h>
27 #include <apt-pkg/tagfile.h>
28 #include <apt-pkg/algorithms.h>
29 #include <apt-pkg/sptr.h>
30
31 #include <config.h>
32 #include <apti18n.h>
33
34 // CNC:2003-02-14 - apti18n.h includes libintl.h which includes locale.h,
35 //                  as reported by Radu Greab.
36 //#include <locale.h>
37 #include <iostream>
38 #include <unistd.h>
39 #include <errno.h>
40 #include <regex.h>
41 #include <stdio.h>
42
43 // CNC:2003-11-23
44 #include <apt-pkg/luaiface.h>
45     
46                                                                         /*}}}*/
47
48 using namespace std;
49
50 pkgCache *GCache = 0;
51 pkgSourceList *SrcList = 0;
52
53 // LocalitySort - Sort a version list by package file locality          /*{{{*/
54 // ---------------------------------------------------------------------
55 /* */
56 int LocalityCompare(const void *a, const void *b)
57 {
58    pkgCache::VerFile *A = *(pkgCache::VerFile **)a;
59    pkgCache::VerFile *B = *(pkgCache::VerFile **)b;
60    
61    if (A == 0 && B == 0)
62       return 0;
63    if (A == 0)
64       return 1;
65    if (B == 0)
66       return -1;
67    
68    if (A->File == B->File)
69       return A->Offset - B->Offset;
70    return A->File - B->File;
71 }
72
73 void LocalitySort(pkgCache::VerFile **begin,
74                   unsigned long Count,size_t Size)
75 {   
76    qsort(begin,Count,Size,LocalityCompare);
77 }
78                                                                         /*}}}*/
79 // CNC:2003-11-23
80 // Script - Scripting stuff.                                            /*{{{*/
81 // ---------------------------------------------------------------------
82 /* */
83 #ifdef WITH_LUA
84 bool Script(CommandLine &CmdL)
85 {
86    for (const char **I = CmdL.FileList+1; *I != 0; I++)
87       _config->Set("Scripts::AptCache::Script::", *I);
88
89    _lua->SetCache(GCache);
90    _lua->RunScripts("Scripts::AptCache::Script");
91    _lua->ResetGlobals();
92
93    return true;
94 }
95 #endif
96                                                                         /*}}}*/
97 // UnMet - Show unmet dependencies                                      /*{{{*/
98 // ---------------------------------------------------------------------
99 /* */
100 bool UnMet(CommandLine &CmdL)
101 {
102    pkgCache &Cache = *GCache;
103    bool Important = _config->FindB("APT::Cache::Important",false);
104    
105    for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
106    {
107       for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; V++)
108       {
109          bool Header = false;
110          for (pkgCache::DepIterator D = V.DependsList(); D.end() == false;)
111          {
112             // Collect or groups
113             pkgCache::DepIterator Start;
114             pkgCache::DepIterator End;
115             D.GlobOr(Start,End);
116             
117             // Skip conflicts and replaces
118             if (End->Type != pkgCache::Dep::PreDepends &&
119                 End->Type != pkgCache::Dep::Depends && 
120                 End->Type != pkgCache::Dep::Suggests &&
121                 End->Type != pkgCache::Dep::Recommends)
122                continue;
123
124             // Important deps only
125             if (Important == true)
126                if (End->Type != pkgCache::Dep::PreDepends &&
127                    End->Type != pkgCache::Dep::Depends)
128                   continue;
129             
130             // Verify the or group
131             bool OK = false;
132             pkgCache::DepIterator RealStart = Start;
133             do
134             {
135                // See if this dep is Ok
136                pkgCache::Version **VList = Start.AllTargets();
137                if (*VList != 0)
138                {
139                   OK = true;
140                   delete [] VList;
141                   break;
142                }
143                delete [] VList;
144                
145                if (Start == End)
146                   break;
147                Start++;
148             }
149             while (1);
150
151             // The group is OK
152             if (OK == true)
153                continue;
154             
155             // Oops, it failed..
156             if (Header == false)
157                ioprintf(cout,_("Package %s version %s has an unmet dep:\n"),
158                         P.Name(),V.VerStr());
159             Header = true;
160             
161             // Print out the dep type
162             cout << " " << End.DepType() << ": ";
163
164             // Show the group
165             Start = RealStart;
166             do
167             {
168                cout << Start.TargetPkg().Name();
169                if (Start.TargetVer() != 0)
170                   cout << " (" << Start.CompType() << " " << Start.TargetVer() <<
171                   ")";
172                if (Start == End)
173                   break;
174                cout << " | ";
175                Start++;
176             }
177             while (1);
178             
179             cout << endl;
180          }       
181       }
182    }   
183    return true;
184 }
185                                                                         /*}}}*/
186 // DumpPackage - Show a dump of a package record                        /*{{{*/
187 // ---------------------------------------------------------------------
188 /* */
189 bool DumpPackage(CommandLine &CmdL)
190 {   
191    pkgCache &Cache = *GCache;
192    for (const char **I = CmdL.FileList + 1; *I != 0; I++)
193    {
194       pkgCache::PkgIterator Pkg = Cache.FindPkg(*I);
195       if (Pkg.end() == true)
196       {
197          _error->Warning(_("Unable to locate package %s"),*I);
198          continue;
199       }
200
201       cout << "Package: " << Pkg.Name() << endl;
202       cout << "Versions: " << endl;
203       for (pkgCache::VerIterator Cur = Pkg.VersionList(); Cur.end() != true; Cur++)
204       {
205          cout << Cur.VerStr();
206          for (pkgCache::VerFileIterator Vf = Cur.FileList(); Vf.end() == false; Vf++)
207             cout << "(" << Vf.File().FileName() << ")";
208          cout << endl;
209       }
210       
211       cout << endl;
212       
213       cout << "Reverse Depends: " << endl;
214       for (pkgCache::DepIterator D = Pkg.RevDependsList(); D.end() != true; D++)
215       {
216          cout << "  " << D.ParentPkg().Name() << ',' << D.TargetPkg().Name();
217          if (D->Version != 0)
218             cout << ' ' << DeNull(D.TargetVer()) << endl;
219          else
220             cout << endl;
221       }
222       
223       cout << "Dependencies: " << endl;
224       for (pkgCache::VerIterator Cur = Pkg.VersionList(); Cur.end() != true; Cur++)
225       {
226          cout << Cur.VerStr() << " - ";
227          for (pkgCache::DepIterator Dep = Cur.DependsList(); Dep.end() != true; Dep++)
228             cout << Dep.TargetPkg().Name() << " (" << (int)Dep->CompareOp << " " << DeNull(Dep.TargetVer()) << ") ";
229          cout << endl;
230       }      
231
232       cout << "Provides: " << endl;
233       for (pkgCache::VerIterator Cur = Pkg.VersionList(); Cur.end() != true; Cur++)
234       {
235          cout << Cur.VerStr() << " - ";
236          for (pkgCache::PrvIterator Prv = Cur.ProvidesList(); Prv.end() != true; Prv++)
237             cout << Prv.ParentPkg().Name() << " ";
238          cout << endl;
239       }
240       cout << "Reverse Provides: " << endl;
241       for (pkgCache::PrvIterator Prv = Pkg.ProvidesList(); Prv.end() != true; Prv++)
242          cout << Prv.OwnerPkg().Name() << " " << Prv.OwnerVer().VerStr() << endl;            
243    }
244
245    return true;
246 }
247                                                                         /*}}}*/
248 // Stats - Dump some nice statistics                                    /*{{{*/
249 // ---------------------------------------------------------------------
250 /* */
251 bool Stats(CommandLine &Cmd)
252 {
253    pkgCache &Cache = *GCache;
254    cout << _("Total Package Names : ") << Cache.Head().PackageCount << " (" <<
255       SizeToStr(Cache.Head().PackageCount*Cache.Head().PackageSz) << ')' << endl;
256
257    int Normal = 0;
258    int Virtual = 0;
259    int NVirt = 0;
260    int DVirt = 0;
261    int Missing = 0;
262    pkgCache::PkgIterator I = Cache.PkgBegin();
263    for (;I.end() != true; I++)
264    {
265       if (I->VersionList != 0 && I->ProvidesList == 0)
266       {
267          Normal++;
268          continue;
269       }
270
271       if (I->VersionList != 0 && I->ProvidesList != 0)
272       {
273          NVirt++;
274          continue;
275       }
276       
277       if (I->VersionList == 0 && I->ProvidesList != 0)
278       {
279          // Only 1 provides
280          if (I.ProvidesList()->NextProvides == 0)
281          {
282             DVirt++;
283          }
284          else
285             Virtual++;
286          continue;
287       }
288       if (I->VersionList == 0 && I->ProvidesList == 0)
289       {
290          Missing++;
291          continue;
292       }
293    }
294    cout << _("  Normal Packages: ") << Normal << endl;
295    cout << _("  Pure Virtual Packages: ") << Virtual << endl;
296    cout << _("  Single Virtual Packages: ") << DVirt << endl;
297    cout << _("  Mixed Virtual Packages: ") << NVirt << endl;
298    cout << _("  Missing: ") << Missing << endl;
299    
300    cout << _("Total Distinct Versions: ") << Cache.Head().VersionCount << " (" <<
301       SizeToStr(Cache.Head().VersionCount*Cache.Head().VersionSz) << ')' << endl;
302    cout << _("Total Dependencies: ") << Cache.Head().DependsCount << " (" << 
303       SizeToStr(Cache.Head().DependsCount*Cache.Head().DependencySz) << ')' << endl;
304    
305    cout << _("Total Ver/File relations: ") << Cache.Head().VerFileCount << " (" <<
306       SizeToStr(Cache.Head().VerFileCount*Cache.Head().VerFileSz) << ')' << endl;
307    cout << _("Total Provides Mappings: ") << Cache.Head().ProvidesCount << " (" <<
308       SizeToStr(Cache.Head().ProvidesCount*Cache.Head().ProvidesSz) << ')' << endl;
309    
310    // String list stats
311    unsigned long Size = 0;
312    unsigned long Count = 0;
313    for (pkgCache::StringItem *I = Cache.StringItemP + Cache.Head().StringList;
314         I!= Cache.StringItemP; I = Cache.StringItemP + I->NextItem)
315    {
316       Count++;
317       Size += strlen(Cache.StrP + I->String) + 1;
318    }
319    cout << _("Total Globbed Strings: ") << Count << " (" << SizeToStr(Size) << ')' << endl;
320
321    unsigned long DepVerSize = 0;
322    for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
323    {
324       for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; V++)
325       {
326          for (pkgCache::DepIterator D = V.DependsList(); D.end() == false; D++)
327          {
328             if (D->Version != 0)
329                DepVerSize += strlen(D.TargetVer()) + 1;
330          }
331       }
332    }
333    cout << _("Total Dependency Version space: ") << SizeToStr(DepVerSize) << endl;
334    
335    unsigned long Slack = 0;
336    for (int I = 0; I != 7; I++)
337       Slack += Cache.Head().Pools[I].ItemSize*Cache.Head().Pools[I].Count;
338    cout << _("Total Slack space: ") << SizeToStr(Slack) << endl;
339    
340    unsigned long Total = 0;
341    Total = Slack + Size + Cache.Head().DependsCount*Cache.Head().DependencySz + 
342            Cache.Head().VersionCount*Cache.Head().VersionSz +
343            Cache.Head().PackageCount*Cache.Head().PackageSz + 
344            Cache.Head().VerFileCount*Cache.Head().VerFileSz +
345            Cache.Head().ProvidesCount*Cache.Head().ProvidesSz;
346    cout << _("Total Space Accounted for: ") << SizeToStr(Total) << endl;
347    
348    return true;
349 }
350                                                                         /*}}}*/
351 // Dump - show everything                                               /*{{{*/
352 // ---------------------------------------------------------------------
353 /* This is worthless except fer debugging things */
354 bool Dump(CommandLine &Cmd)
355 {
356    pkgCache &Cache = *GCache;
357    cout << "Using Versioning System: " << Cache.VS->Label << endl;
358    
359    for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
360    {
361       cout << "Package: " << P.Name() << endl;
362       for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; V++)
363       {
364          cout << " Version: " << V.VerStr() << endl;
365          cout << "     File: " << V.FileList().File().FileName() << endl;
366          for (pkgCache::DepIterator D = V.DependsList(); D.end() == false; D++)
367             cout << "  Depends: " << D.TargetPkg().Name() << ' ' << 
368                              DeNull(D.TargetVer()) << endl;
369       }      
370    }
371
372    for (pkgCache::PkgFileIterator F = Cache.FileBegin(); F.end() == false; F++)
373    {
374       cout << "File: " << F.FileName() << endl;
375       cout << " Type: " << F.IndexType() << endl;
376       cout << " Size: " << F->Size << endl;
377       cout << " ID: " << F->ID << endl;
378       cout << " Flags: " << F->Flags << endl;
379       cout << " Time: " << TimeRFC1123(F->mtime) << endl;
380       cout << " Archive: " << DeNull(F.Archive()) << endl;
381       cout << " Component: " << DeNull(F.Component()) << endl;
382       cout << " Version: " << DeNull(F.Version()) << endl;
383       cout << " Origin: " << DeNull(F.Origin()) << endl;
384       cout << " Site: " << DeNull(F.Site()) << endl;
385       cout << " Label: " << DeNull(F.Label()) << endl;
386       cout << " Architecture: " << DeNull(F.Architecture()) << endl;
387    }
388
389    return true;
390 }
391                                                                         /*}}}*/
392 // DumpAvail - Print out the available list                             /*{{{*/
393 // ---------------------------------------------------------------------
394 /* This is needed to make dpkg --merge happy.. I spent a bit of time to 
395    make this run really fast, perhaps I went a little overboard.. */
396 bool DumpAvail(CommandLine &Cmd)
397 {
398    pkgCache &Cache = *GCache;
399
400    pkgPolicy Plcy(&Cache);
401    if (ReadPinFile(Plcy) == false)
402       return false;
403    
404    unsigned long Count = Cache.HeaderP->PackageCount+1;
405    pkgCache::VerFile **VFList = new pkgCache::VerFile *[Count];
406    memset(VFList,0,sizeof(*VFList)*Count);
407    
408    // Map versions that we want to write out onto the VerList array.
409    for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
410    {    
411       if (P->VersionList == 0)
412          continue;
413       
414       /* Find the proper version to use. If the policy says there are no
415          possible selections we return the installed version, if available..
416          This prevents dselect from making it obsolete. */
417       pkgCache::VerIterator V = Plcy.GetCandidateVer(P);
418       if (V.end() == true)
419       {
420          if (P->CurrentVer == 0)
421             continue;
422          V = P.CurrentVer();
423       }
424       
425       pkgCache::VerFileIterator VF = V.FileList();
426       for (; VF.end() == false ; VF++)
427          if ((VF.File()->Flags & pkgCache::Flag::NotSource) == 0)
428             break;
429       
430       /* Okay, here we have a bit of a problem.. The policy has selected the
431          currently installed package - however it only exists in the
432          status file.. We need to write out something or dselect will mark
433          the package as obsolete! Thus we emit the status file entry, but
434          below we remove the status line to make it valid for the 
435          available file. However! We only do this if their do exist *any*
436          non-source versions of the package - that way the dselect obsolete
437          handling works OK. */
438       if (VF.end() == true)
439       {
440          for (pkgCache::VerIterator Cur = P.VersionList(); Cur.end() != true; Cur++)
441          {
442             for (VF = Cur.FileList(); VF.end() == false; VF++)
443             {    
444                if ((VF.File()->Flags & pkgCache::Flag::NotSource) == 0)
445                {
446                   VF = V.FileList();
447                   break;
448                }
449             }
450             
451             if (VF.end() == false)
452                break;
453          }
454       }
455       
456 // CNC:2002-07-24
457 #if HAVE_RPM
458       if (VF.end() == false)
459       {
460          pkgRecords Recs(Cache);
461          pkgRecords::Parser &P = Recs.Lookup(VF);
462          const char *Start;
463          const char *End;
464          P.GetRec(Start,End);
465          fwrite(Start,End-Start,1,stdout);
466          putc('\n',stdout);
467       }
468    }
469    return !_error->PendingError();
470 #else
471       VFList[P->ID] = VF;
472    }
473 #endif
474    
475    LocalitySort(VFList,Count,sizeof(*VFList));
476
477    // Iterate over all the package files and write them out.
478    char *Buffer = new char[Cache.HeaderP->MaxVerFileSize+10];
479    for (pkgCache::VerFile **J = VFList; *J != 0;)
480    {
481       pkgCache::PkgFileIterator File(Cache,(*J)->File + Cache.PkgFileP);
482       if (File.IsOk() == false)
483       {
484          _error->Error(_("Package file %s is out of sync."),File.FileName());
485          break;
486       }
487
488       FileFd PkgF(File.FileName(),FileFd::ReadOnly);
489       if (_error->PendingError() == true)
490          break;
491       
492       /* Write all of the records from this package file, since we
493          already did locality sorting we can now just seek through the
494          file in read order. We apply 1 more optimization here, since often
495          there will be < 1 byte gaps between records (for the \n) we read that
496          into the next buffer and offset a bit.. */
497       unsigned long Pos = 0;
498       for (; *J != 0; J++)
499       {
500          if ((*J)->File + Cache.PkgFileP != File)
501             break;
502          
503          const pkgCache::VerFile &VF = **J;
504
505          // Read the record and then write it out again.
506          unsigned long Jitter = VF.Offset - Pos;
507          if (Jitter > 8)
508          {
509             if (PkgF.Seek(VF.Offset) == false)
510                break;
511             Jitter = 0;
512          }
513          
514          if (PkgF.Read(Buffer,VF.Size + Jitter) == false)
515             break;
516          Buffer[VF.Size + Jitter] = '\n';
517          
518          // See above..
519          if ((File->Flags & pkgCache::Flag::NotSource) == pkgCache::Flag::NotSource)
520          {
521             pkgTagSection Tags;
522             TFRewriteData RW[] = {{"Status",0},{"Config-Version",0},{}};
523             const char *Zero = 0;
524             if (Tags.Scan(Buffer+Jitter,VF.Size+1) == false ||
525                 TFRewrite(stdout,Tags,&Zero,RW) == false)
526             {
527                _error->Error("Internal Error, Unable to parse a package record");
528                break;
529             }
530             fputc('\n',stdout);
531          }
532          else
533          {
534             if (fwrite(Buffer+Jitter,VF.Size+1,1,stdout) != 1)
535                break;
536          }
537          
538          Pos = VF.Offset + VF.Size;
539       }
540
541       fflush(stdout);
542       if (_error->PendingError() == true)
543          break;
544    }
545    
546    delete [] Buffer;
547    delete [] VFList;
548    return !_error->PendingError();
549 }
550                                                                         /*}}}*/
551 // Depends - Print out a dependency tree                                /*{{{*/
552 // ---------------------------------------------------------------------
553 /* */
554 bool Depends(CommandLine &CmdL)
555 {
556    pkgCache &Cache = *GCache;
557    SPtrArray<unsigned> Colours = new unsigned[Cache.Head().PackageCount];
558    memset(Colours,0,sizeof(*Colours)*Cache.Head().PackageCount);
559    
560    for (const char **I = CmdL.FileList + 1; *I != 0; I++)
561    {
562       pkgCache::PkgIterator Pkg = Cache.FindPkg(*I);
563       if (Pkg.end() == true)
564       {
565          _error->Warning(_("Unable to locate package %s"),*I);
566          continue;
567       }
568       Colours[Pkg->ID] = 1;
569    }
570    
571    bool Recurse = _config->FindB("APT::Cache::RecurseDepends",false);
572    bool Installed = _config->FindB("APT::Cache::Installed",false);
573    bool DidSomething;
574    do
575    {
576       DidSomething = false;
577       for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++)
578       {
579          if (Colours[Pkg->ID] != 1)
580             continue;
581          Colours[Pkg->ID] = 2;
582          DidSomething = true;
583          
584          pkgCache::VerIterator Ver = Pkg.VersionList();
585          if (Ver.end() == true)
586          {
587             cout << '<' << Pkg.Name() << '>' << endl;
588             continue;
589          }
590          
591          // CNC:2003-03-03
592          cout << Pkg.Name() << "-" << Ver.VerStr() << endl;
593          
594          for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; D++)
595          {
596
597             pkgCache::PkgIterator Trg = D.TargetPkg();
598
599             if((Installed && Trg->CurrentVer != 0) || !Installed)
600               {
601
602                 if ((D->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or)
603                   cout << " |";
604                 else
605                   cout << "  ";
606             
607                 // Show the package
608                 if (Trg->VersionList == 0)
609                    cout << D.DepType() << ": <" << Trg.Name() << ">" << endl;
610                 // CNC:2003-03-03
611                 else if (D.TargetVer() == 0)
612                    cout << D.DepType() << ": " << Trg.Name() << endl;
613                 else
614                    cout << D.DepType() << ": " << Trg.Name()
615                         << " " << D.CompType() << " " << D.TargetVer() << endl;
616             
617                 if (Recurse == true)
618                   Colours[D.TargetPkg()->ID]++;
619
620               }
621             
622             // Display all solutions
623             SPtrArray<pkgCache::Version *> List = D.AllTargets();
624             pkgPrioSortList(Cache,List);
625             for (pkgCache::Version **I = List; *I != 0; I++)
626             {
627                pkgCache::VerIterator V(Cache,*I);
628                if (V != Cache.VerP + V.ParentPkg()->VersionList ||
629                    V->ParentPkg == D->Package)
630                   continue;
631                // CNC:2003-03-03
632                cout << "    " << V.ParentPkg().Name()
633                     << "-" << V.VerStr() << endl;
634                
635                if (Recurse == true)
636                   Colours[D.ParentPkg()->ID]++;
637             }
638          }
639       }      
640    }   
641    while (DidSomething == true);
642    
643    return true;
644 }
645
646 // RDepends - Print out a reverse dependency tree - mbc                 /*{{{*/
647 // ---------------------------------------------------------------------
648 /* */
649 bool RDepends(CommandLine &CmdL)
650 {
651    pkgCache &Cache = *GCache;
652    SPtrArray<unsigned> Colours = new unsigned[Cache.Head().PackageCount];
653    memset(Colours,0,sizeof(*Colours)*Cache.Head().PackageCount);
654    
655    for (const char **I = CmdL.FileList + 1; *I != 0; I++)
656    {
657       pkgCache::PkgIterator Pkg = Cache.FindPkg(*I);
658       if (Pkg.end() == true)
659       {
660          _error->Warning(_("Unable to locate package %s"),*I);
661          continue;
662       }
663       Colours[Pkg->ID] = 1;
664    }
665    
666    bool Recurse = _config->FindB("APT::Cache::RecurseDepends",false);
667    bool Installed = _config->FindB("APT::Cache::Installed",false);
668    bool DidSomething;
669    do
670    {
671       DidSomething = false;
672       for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++)
673       {
674          if (Colours[Pkg->ID] != 1)
675             continue;
676          Colours[Pkg->ID] = 2;
677          DidSomething = true;
678          
679          pkgCache::VerIterator Ver = Pkg.VersionList();
680          if (Ver.end() == true)
681          {
682             cout << '<' << Pkg.Name() << '>' << endl;
683             continue;
684          }
685          
686          cout << Pkg.Name() << endl;
687          
688          cout << "Reverse Depends:" << endl;
689          for (pkgCache::DepIterator D = Pkg.RevDependsList(); D.end() == false; D++)
690          {          
691             // Show the package
692             pkgCache::PkgIterator Trg = D.ParentPkg();
693
694             if((Installed && Trg->CurrentVer != 0) || !Installed)
695               {
696
697                 if ((D->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or)
698                   cout << " |";
699                 else
700                   cout << "  ";
701
702                 if (Trg->VersionList == 0)
703                   cout << D.DepType() << ": <" << Trg.Name() << ">" << endl;
704                 else
705                   cout << Trg.Name() << endl;
706
707                 if (Recurse == true)
708                   Colours[D.ParentPkg()->ID]++;
709
710               }
711             
712             // Display all solutions
713             SPtrArray<pkgCache::Version *> List = D.AllTargets();
714             pkgPrioSortList(Cache,List);
715             for (pkgCache::Version **I = List; *I != 0; I++)
716             {
717                pkgCache::VerIterator V(Cache,*I);
718                if (V != Cache.VerP + V.ParentPkg()->VersionList ||
719                    V->ParentPkg == D->Package)
720                   continue;
721                cout << "    " << V.ParentPkg().Name() << endl;
722                
723                if (Recurse == true)
724                   Colours[D.ParentPkg()->ID]++;
725             }
726          }
727       }      
728    }   
729    while (DidSomething == true);
730    
731    return true;
732 }
733
734                                                                         /*}}}*/
735 // CNC:2003-02-19
736 // WhatDepends - Print out a reverse dependency tree                    /*{{{*/
737 // ---------------------------------------------------------------------
738 /* */
739 bool WhatDepends(CommandLine &CmdL)
740 {
741    pkgCache &Cache = *GCache;
742    SPtrArray<unsigned> Colours = new unsigned[Cache.Head().PackageCount];
743    memset(Colours,0,sizeof(*Colours)*Cache.Head().PackageCount);
744    
745    for (const char **I = CmdL.FileList + 1; *I != 0; I++)
746    {
747       pkgCache::PkgIterator Pkg = Cache.FindPkg(*I);
748       if (Pkg.end() == true)
749       {
750          _error->Warning(_("Unable to locate package %s"),*I);
751          continue;
752       }
753       Colours[Pkg->ID] = 1;
754    }
755    
756    bool Recurse = _config->FindB("APT::Cache::RecurseDepends",false);
757    bool DidSomething;
758    do
759    {
760       DidSomething = false;
761       for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++)
762       {
763          if (Colours[Pkg->ID] != 1)
764             continue;
765          Colours[Pkg->ID] = 2;
766          DidSomething = true;
767          
768          pkgCache::VerIterator Ver = Pkg.VersionList();
769          if (Ver.end() == true)
770             cout << '<' << Pkg.Name() << '>' << endl;
771          else
772             cout << Pkg.Name() << "-" << Ver.VerStr() << endl;
773
774          SPtrArray<unsigned> LocalColours = 
775                      new unsigned[Cache.Head().PackageCount];
776          memset(LocalColours,0,sizeof(*LocalColours)*Cache.Head().PackageCount);
777             
778          // Display all dependencies directly on the package.
779          for (pkgCache::DepIterator RD = Pkg.RevDependsList();
780               RD.end() == false; RD++)
781          {
782             pkgCache::PkgIterator Parent = RD.ParentPkg();
783
784             if (LocalColours[Parent->ID] == 1)
785                continue;
786             LocalColours[Parent->ID] = 1;
787                
788             if (Ver.end() == false && RD.TargetVer() &&
789                 Cache.VS->CheckDep(Ver.VerStr(),RD) == false)
790                continue;
791
792             if (Recurse == true && Colours[Parent->ID] == 0)
793                Colours[Parent->ID] = 1;
794
795             pkgCache::VerIterator ParentVer = Parent.VersionList();
796
797             // Show the package
798             cout << "  " << Parent.Name()
799                  << "-" << ParentVer.VerStr() << endl;
800
801             // Display all dependencies from that package that relate
802             // to the queried package.
803             for (pkgCache::DepIterator D = ParentVer.DependsList();
804                  D.end() == false; D++)
805             {
806                // If this is a virtual package, there's no provides.
807                if (Ver.end() == true) {
808                   // If it's not the same package, and there's no provides
809                   // skip that package.
810                   if (D.TargetPkg() != Pkg)
811                      continue;
812                } else if (D.TargetPkg() != Pkg ||
813                           Cache.VS->CheckDep(Ver.VerStr(),D) == false) {
814                   // Oops. Either it's not the same package, or the
815                   // version didn't match. Check virtual provides from
816                   // the queried package version and verify if this
817                   // dependency matches one of those.
818                   bool Hit = false;
819                   for (pkgCache::PrvIterator Prv = Ver.ProvidesList();
820                        Prv.end() == false; Prv++) {
821                      if (Prv.ParentPkg() == D.TargetPkg() &&
822                          (Prv.ParentPkg()->VersionList == 0 ||
823                           Cache.VS->CheckDep(Prv.ProvideVersion(),D)==false)) {
824                         Hit = true;
825                         break;
826                      }
827                   }
828                   if (Hit == false)
829                      continue;
830                }
831
832                // Bingo!
833                pkgCache::PkgIterator Trg = D.TargetPkg();
834                if (Trg->VersionList == 0)
835                   cout << "    " << D.DepType()
836                                  << ": <" << Trg.Name() << ">" << endl;
837                else if (D.TargetVer() == 0)
838                   cout << "    " << D.DepType()
839                                  << ": " << Trg.Name() << endl;
840                else
841                   cout << "    " << D.DepType()
842                                  << ": " << Trg.Name()
843                                  << " " << D.CompType() << " "
844                                  << D.TargetVer() << endl;
845
846                // Display all solutions
847                SPtrArray<pkgCache::Version *> List = D.AllTargets();
848                pkgPrioSortList(Cache,List);
849                for (pkgCache::Version **I = List; *I != 0; I++)
850                {
851                   pkgCache::VerIterator V(Cache,*I);
852                   if (V != Cache.VerP + V.ParentPkg()->VersionList ||
853                       V->ParentPkg == D->Package)
854                      continue;
855                   cout << "      " << V.ParentPkg().Name()
856                        << "-" << V.VerStr() << endl;
857                   
858                   if (Recurse == true)
859                      Colours[D.ParentPkg()->ID]++;
860                }
861             }
862          }
863
864          // Is this a virtual package the user queried directly?
865          if (Ver.end())
866             continue;
867
868          // Display all dependencies on virtual provides, which were not
869          // yet shown in the step above.
870          for (pkgCache::PrvIterator RDPrv = Ver.ProvidesList();
871               RDPrv.end() == false; RDPrv++) {
872             for (pkgCache::DepIterator RD = RDPrv.ParentPkg().RevDependsList();
873                  RD.end() == false; RD++)
874             {
875                pkgCache::PkgIterator Parent = RD.ParentPkg();
876
877                if (LocalColours[Parent->ID] == 1)
878                   continue;
879                LocalColours[Parent->ID] = 1;
880                   
881                if (Ver.end() == false &&
882                    Cache.VS->CheckDep(Ver.VerStr(),RD) == false)
883                   continue;
884
885                if (Recurse == true && Colours[Parent->ID] == 0)
886                   Colours[Parent->ID] = 1;
887
888                pkgCache::VerIterator ParentVer = Parent.VersionList();
889
890                // Show the package
891                cout << "  " << Parent.Name()
892                     << "-" << ParentVer.VerStr() << endl;
893
894                for (pkgCache::DepIterator D = ParentVer.DependsList();
895                     D.end() == false; D++)
896                {
897                   // Go on if it's the same package and version or
898                   // if it's the same package and has no versions
899                   // (a virtual package).
900                   if (D.TargetPkg() != RDPrv.ParentPkg() ||
901                       (RDPrv.ProvideVersion() != 0 &&
902                        Cache.VS->CheckDep(RDPrv.ProvideVersion(),D) == false))
903                      continue;
904
905                   // Bingo!
906                   pkgCache::PkgIterator Trg = D.TargetPkg();
907                   if (Trg->VersionList == 0)
908                      cout << "    " << D.DepType()
909                                     << ": <" << Trg.Name() << ">" << endl;
910                   else if (D.TargetVer() == 0)
911                      cout << "    " << D.DepType()
912                                     << ": " << Trg.Name() << endl;
913                   else
914                      cout << "    " << D.DepType()
915                                     << ": " << Trg.Name()
916                                     << " " << D.CompType() << " "
917                                     << D.TargetVer() << endl;
918
919                   // Display all solutions
920                   SPtrArray<pkgCache::Version *> List = D.AllTargets();
921                   pkgPrioSortList(Cache,List);
922                   for (pkgCache::Version **I = List; *I != 0; I++)
923                   {
924                      pkgCache::VerIterator V(Cache,*I);
925                      if (V != Cache.VerP + V.ParentPkg()->VersionList ||
926                          V->ParentPkg == D->Package)
927                         continue;
928                      cout << "      " << V.ParentPkg().Name()
929                           << "-" << V.VerStr() << endl;
930                      
931                      if (Recurse == true)
932                         Colours[D.ParentPkg()->ID]++;
933                   }
934                }
935             }
936          }
937       } 
938    }
939    while (DidSomething == true);
940    
941    return true;
942 }
943                                                                         /*}}}*/
944
945 // xvcg - Generate a graph for xvcg                                     /*{{{*/
946 // ---------------------------------------------------------------------
947 // Code contributed from Junichi Uekawa <dancer@debian.org> on 20 June 2002.
948
949 bool XVcg(CommandLine &CmdL)
950 {
951    pkgCache &Cache = *GCache;
952    bool GivenOnly = _config->FindB("APT::Cache::GivenOnly",false);
953    
954    /* Normal packages are boxes
955       Pure Provides are triangles
956       Mixed are diamonds
957       rhomb are missing packages*/
958    const char *Shapes[] = {"ellipse","triangle","box","rhomb"};
959    
960    /* Initialize the list of packages to show.
961       1 = To Show
962       2 = To Show no recurse
963       3 = Emitted no recurse
964       4 = Emitted
965       0 = None */
966    enum States {None=0, ToShow, ToShowNR, DoneNR, Done};
967    enum TheFlags {ForceNR=(1<<0)};
968    unsigned char *Show = new unsigned char[Cache.Head().PackageCount];
969    unsigned char *Flags = new unsigned char[Cache.Head().PackageCount];
970    unsigned char *ShapeMap = new unsigned char[Cache.Head().PackageCount];
971    
972    // Show everything if no arguments given
973    if (CmdL.FileList[1] == 0)
974       for (unsigned long I = 0; I != Cache.Head().PackageCount; I++)
975          Show[I] = ToShow;
976    else
977       for (unsigned long I = 0; I != Cache.Head().PackageCount; I++)
978          Show[I] = None;
979    memset(Flags,0,sizeof(*Flags)*Cache.Head().PackageCount);
980    
981    // Map the shapes
982    for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++)
983    {   
984       if (Pkg->VersionList == 0)
985       {
986          // Missing
987          if (Pkg->ProvidesList == 0)
988             ShapeMap[Pkg->ID] = 0;
989          else
990             ShapeMap[Pkg->ID] = 1;
991       }
992       else
993       {
994          // Normal
995          if (Pkg->ProvidesList == 0)
996             ShapeMap[Pkg->ID] = 2;
997          else
998             ShapeMap[Pkg->ID] = 3;
999       }
1000    }
1001    
1002    // Load the list of packages from the command line into the show list
1003    for (const char **I = CmdL.FileList + 1; *I != 0; I++)
1004    {
1005       // Process per-package flags
1006       string P = *I;
1007       bool Force = false;
1008       if (P.length() > 3)
1009       {
1010          if (P.end()[-1] == '^')
1011          {
1012             Force = true;
1013             P.erase(P.end()-1);
1014          }
1015          
1016          if (P.end()[-1] == ',')
1017             P.erase(P.end()-1);
1018       }
1019       
1020       // Locate the package
1021       pkgCache::PkgIterator Pkg = Cache.FindPkg(P);
1022       if (Pkg.end() == true)
1023       {
1024          _error->Warning(_("Unable to locate package %s"),*I);
1025          continue;
1026       }
1027       Show[Pkg->ID] = ToShow;
1028       
1029       if (Force == true)
1030          Flags[Pkg->ID] |= ForceNR;
1031    }
1032    
1033    // Little header
1034    cout << "graph: { title: \"packages\"" << endl <<
1035      "xmax: 700 ymax: 700 x: 30 y: 30" << endl <<
1036      "layout_downfactor: 8" << endl;
1037
1038    bool Act = true;
1039    while (Act == true)
1040    {
1041       Act = false;
1042       for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++)
1043       {
1044          // See we need to show this package
1045          if (Show[Pkg->ID] == None || Show[Pkg->ID] >= DoneNR)
1046             continue;
1047
1048          //printf ("node: { title: \"%s\" label: \"%s\" }\n", Pkg.Name(), Pkg.Name());
1049          
1050          // Colour as done
1051          if (Show[Pkg->ID] == ToShowNR || (Flags[Pkg->ID] & ForceNR) == ForceNR)
1052          {
1053             // Pure Provides and missing packages have no deps!
1054             if (ShapeMap[Pkg->ID] == 0 || ShapeMap[Pkg->ID] == 1)
1055                Show[Pkg->ID] = Done;
1056             else
1057                Show[Pkg->ID] = DoneNR;
1058          }       
1059          else
1060             Show[Pkg->ID] = Done;
1061          Act = true;
1062
1063          // No deps to map out
1064          if (Pkg->VersionList == 0 || Show[Pkg->ID] == DoneNR)
1065             continue;
1066          
1067          pkgCache::VerIterator Ver = Pkg.VersionList();
1068          for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; D++)
1069          {
1070             // See if anything can meet this dep
1071             // Walk along the actual package providing versions
1072             bool Hit = false;
1073             pkgCache::PkgIterator DPkg = D.TargetPkg();
1074             for (pkgCache::VerIterator I = DPkg.VersionList();
1075                       I.end() == false && Hit == false; I++)
1076             {
1077                if (Cache.VS->CheckDep(I.VerStr(),D->CompareOp,D.TargetVer()) == true)
1078                   Hit = true;
1079             }
1080             
1081             // Follow all provides
1082             for (pkgCache::PrvIterator I = DPkg.ProvidesList(); 
1083                       I.end() == false && Hit == false; I++)
1084             {
1085                if (Cache.VS->CheckDep(I.ProvideVersion(),D->CompareOp,D.TargetVer()) == false)
1086                   Hit = true;
1087             }
1088             
1089
1090             // Only graph critical deps     
1091             if (D.IsCritical() == true)
1092             {
1093                printf ("edge: { sourcename: \"%s\" targetname: \"%s\" class: 2 ",Pkg.Name(), D.TargetPkg().Name() );
1094                
1095                // Colour the node for recursion
1096                if (Show[D.TargetPkg()->ID] <= DoneNR)
1097                {
1098                   /* If a conflicts does not meet anything in the database
1099                      then show the relation but do not recurse */
1100                   if (Hit == false && 
1101                       (D->Type == pkgCache::Dep::Conflicts ||
1102                        D->Type == pkgCache::Dep::Obsoletes))
1103                   {
1104                      if (Show[D.TargetPkg()->ID] == None && 
1105                          Show[D.TargetPkg()->ID] != ToShow)
1106                         Show[D.TargetPkg()->ID] = ToShowNR;
1107                   }               
1108                   else
1109                   {
1110                      if (GivenOnly == true && Show[D.TargetPkg()->ID] != ToShow)
1111                         Show[D.TargetPkg()->ID] = ToShowNR;
1112                      else
1113                         Show[D.TargetPkg()->ID] = ToShow;
1114                   }
1115                }
1116                
1117                // Edge colour
1118                switch(D->Type)
1119                {
1120                   case pkgCache::Dep::Conflicts:
1121                     printf("label: \"conflicts\" color: lightgreen }\n");
1122                     break;
1123                   case pkgCache::Dep::Obsoletes:
1124                     printf("label: \"obsoletes\" color: lightgreen }\n");
1125                     break;
1126                   
1127                   case pkgCache::Dep::PreDepends:
1128                     printf("label: \"predepends\" color: blue }\n");
1129                     break;
1130                   
1131                   default:
1132                     printf("}\n");
1133                   break;
1134                }               
1135             }       
1136          }
1137       }
1138    }   
1139    
1140    /* Draw the box colours after the fact since we can not tell what colour
1141       they should be until everything is finished drawing */
1142    for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++)
1143    {
1144       if (Show[Pkg->ID] < DoneNR)
1145          continue;
1146
1147       if (Show[Pkg->ID] == DoneNR)
1148          printf("node: { title: \"%s\" label: \"%s\" color: orange shape: %s }\n", Pkg.Name(), Pkg.Name(),
1149                 Shapes[ShapeMap[Pkg->ID]]);
1150       else
1151         printf("node: { title: \"%s\" label: \"%s\" shape: %s }\n", Pkg.Name(), Pkg.Name(), 
1152                 Shapes[ShapeMap[Pkg->ID]]);
1153       
1154    }
1155    
1156    printf("}\n");
1157    return true;
1158 }
1159                                                                         /*}}}*/
1160
1161
1162 // Dotty - Generate a graph for Dotty                                   /*{{{*/
1163 // ---------------------------------------------------------------------
1164 /* Dotty is the graphvis program for generating graphs. It is a fairly
1165    simple queuing algorithm that just writes dependencies and nodes. 
1166    http://www.research.att.com/sw/tools/graphviz/ */
1167 bool Dotty(CommandLine &CmdL)
1168 {
1169    pkgCache &Cache = *GCache;
1170    bool GivenOnly = _config->FindB("APT::Cache::GivenOnly",false);
1171    
1172    /* Normal packages are boxes
1173       Pure Provides are triangles
1174       Mixed are diamonds
1175       Hexagons are missing packages*/
1176    const char *Shapes[] = {"hexagon","triangle","box","diamond"};
1177    
1178    /* Initialize the list of packages to show.
1179       1 = To Show
1180       2 = To Show no recurse
1181       3 = Emitted no recurse
1182       4 = Emitted
1183       0 = None */
1184    enum States {None=0, ToShow, ToShowNR, DoneNR, Done};
1185    enum TheFlags {ForceNR=(1<<0)};
1186    unsigned char *Show = new unsigned char[Cache.Head().PackageCount];
1187    unsigned char *Flags = new unsigned char[Cache.Head().PackageCount];
1188    unsigned char *ShapeMap = new unsigned char[Cache.Head().PackageCount];
1189    
1190    // Show everything if no arguments given
1191    if (CmdL.FileList[1] == 0)
1192       for (unsigned long I = 0; I != Cache.Head().PackageCount; I++)
1193          Show[I] = ToShow;
1194    else
1195       for (unsigned long I = 0; I != Cache.Head().PackageCount; I++)
1196          Show[I] = None;
1197    memset(Flags,0,sizeof(*Flags)*Cache.Head().PackageCount);
1198    
1199    // Map the shapes
1200    for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++)
1201    {   
1202       if (Pkg->VersionList == 0)
1203       {
1204          // Missing
1205          if (Pkg->ProvidesList == 0)
1206             ShapeMap[Pkg->ID] = 0;
1207          else
1208             ShapeMap[Pkg->ID] = 1;
1209       }
1210       else
1211       {
1212          // Normal
1213          if (Pkg->ProvidesList == 0)
1214             ShapeMap[Pkg->ID] = 2;
1215          else
1216             ShapeMap[Pkg->ID] = 3;
1217       }
1218    }
1219    
1220    // Load the list of packages from the command line into the show list
1221    for (const char **I = CmdL.FileList + 1; *I != 0; I++)
1222    {
1223       // Process per-package flags
1224       string P = *I;
1225       bool Force = false;
1226       if (P.length() > 3)
1227       {
1228          if (P.end()[-1] == '^')
1229          {
1230             Force = true;
1231             P.erase(P.end()-1);
1232          }
1233          
1234          if (P.end()[-1] == ',')
1235             P.erase(P.end()-1);
1236       }
1237       
1238       // Locate the package
1239       pkgCache::PkgIterator Pkg = Cache.FindPkg(P);
1240       if (Pkg.end() == true)
1241       {
1242          _error->Warning(_("Unable to locate package %s"),*I);
1243          continue;
1244       }
1245       Show[Pkg->ID] = ToShow;
1246       
1247       if (Force == true)
1248          Flags[Pkg->ID] |= ForceNR;
1249    }
1250    
1251    // Little header
1252    printf("digraph packages {\n");
1253    printf("concentrate=true;\n");
1254    printf("size=\"30,40\";\n");
1255    
1256    bool Act = true;
1257    while (Act == true)
1258    {
1259       Act = false;
1260       for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++)
1261       {
1262          // See we need to show this package
1263          if (Show[Pkg->ID] == None || Show[Pkg->ID] >= DoneNR)
1264             continue;
1265          
1266          // Colour as done
1267          if (Show[Pkg->ID] == ToShowNR || (Flags[Pkg->ID] & ForceNR) == ForceNR)
1268          {
1269             // Pure Provides and missing packages have no deps!
1270             if (ShapeMap[Pkg->ID] == 0 || ShapeMap[Pkg->ID] == 1)
1271                Show[Pkg->ID] = Done;
1272             else
1273                Show[Pkg->ID] = DoneNR;
1274          }       
1275          else
1276             Show[Pkg->ID] = Done;
1277          Act = true;
1278
1279          // No deps to map out
1280          if (Pkg->VersionList == 0 || Show[Pkg->ID] == DoneNR)
1281             continue;
1282          
1283          pkgCache::VerIterator Ver = Pkg.VersionList();
1284          for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; D++)
1285          {
1286             // See if anything can meet this dep
1287             // Walk along the actual package providing versions
1288             bool Hit = false;
1289             pkgCache::PkgIterator DPkg = D.TargetPkg();
1290             for (pkgCache::VerIterator I = DPkg.VersionList();
1291                       I.end() == false && Hit == false; I++)
1292             {
1293                if (Cache.VS->CheckDep(I.VerStr(),D->CompareOp,D.TargetVer()) == true)
1294                   Hit = true;
1295             }
1296             
1297             // Follow all provides
1298             for (pkgCache::PrvIterator I = DPkg.ProvidesList(); 
1299                       I.end() == false && Hit == false; I++)
1300             {
1301                if (Cache.VS->CheckDep(I.ProvideVersion(),D->CompareOp,D.TargetVer()) == false)
1302                   Hit = true;
1303             }
1304             
1305             // Only graph critical deps     
1306             if (D.IsCritical() == true)
1307             {
1308                printf("\"%s\" -> \"%s\"",Pkg.Name(),D.TargetPkg().Name());
1309                
1310                // Colour the node for recursion
1311                if (Show[D.TargetPkg()->ID] <= DoneNR)
1312                {
1313                   /* If a conflicts does not meet anything in the database
1314                      then show the relation but do not recurse */
1315                   if (Hit == false && 
1316                       (D->Type == pkgCache::Dep::Conflicts ||
1317                        D->Type == pkgCache::Dep::Obsoletes))
1318                   {
1319                      if (Show[D.TargetPkg()->ID] == None && 
1320                          Show[D.TargetPkg()->ID] != ToShow)
1321                         Show[D.TargetPkg()->ID] = ToShowNR;
1322                   }               
1323                   else
1324                   {
1325                      if (GivenOnly == true && Show[D.TargetPkg()->ID] != ToShow)
1326                         Show[D.TargetPkg()->ID] = ToShowNR;
1327                      else
1328                         Show[D.TargetPkg()->ID] = ToShow;
1329                   }
1330                }
1331                
1332                // Edge colour
1333                switch(D->Type)
1334                {
1335                   case pkgCache::Dep::Conflicts:
1336                   case pkgCache::Dep::Obsoletes:
1337                   printf("[color=springgreen];\n");
1338                   break;
1339                   
1340                   case pkgCache::Dep::PreDepends:
1341                   printf("[color=blue];\n");
1342                   break;
1343                   
1344                   default:
1345                   printf(";\n");
1346                   break;
1347                }               
1348             }       
1349          }
1350       }
1351    }   
1352    
1353    /* Draw the box colours after the fact since we can not tell what colour
1354       they should be until everything is finished drawing */
1355    for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++)
1356    {
1357       if (Show[Pkg->ID] < DoneNR)
1358          continue;
1359       
1360       // Orange box for early recursion stoppage
1361       if (Show[Pkg->ID] == DoneNR)
1362          printf("\"%s\" [color=orange,shape=%s];\n",Pkg.Name(),
1363                 Shapes[ShapeMap[Pkg->ID]]);
1364       else
1365          printf("\"%s\" [shape=%s];\n",Pkg.Name(),
1366                 Shapes[ShapeMap[Pkg->ID]]);
1367    }
1368    
1369    printf("}\n");
1370    return true;
1371 }
1372                                                                         /*}}}*/
1373 // DoAdd - Perform an adding operation                                  /*{{{*/
1374 // ---------------------------------------------------------------------
1375 /* */
1376 bool DoAdd(CommandLine &CmdL)
1377 {
1378    return _error->Error("Unimplemented");
1379 #if 0   
1380    // Make sure there is at least one argument
1381    if (CmdL.FileSize() <= 1)
1382       return _error->Error("You must give at least one file name");
1383    
1384    // Open the cache
1385    FileFd CacheF(_config->FindFile("Dir::Cache::pkgcache"),FileFd::WriteAny);
1386    if (_error->PendingError() == true)
1387       return false;
1388    
1389    DynamicMMap Map(CacheF,MMap::Public);
1390    if (_error->PendingError() == true)
1391       return false;
1392
1393    OpTextProgress Progress(*_config);
1394    pkgCacheGenerator Gen(Map,Progress);
1395    if (_error->PendingError() == true)
1396       return false;
1397
1398    unsigned long Length = CmdL.FileSize() - 1;
1399    for (const char **I = CmdL.FileList + 1; *I != 0; I++)
1400    {
1401       Progress.OverallProgress(I - CmdL.FileList,Length,1,"Generating cache");
1402       Progress.SubProgress(Length);
1403
1404       // Do the merge
1405       FileFd TagF(*I,FileFd::ReadOnly);
1406       debListParser Parser(TagF);
1407       if (_error->PendingError() == true)
1408          return _error->Error("Problem opening %s",*I);
1409       
1410       if (Gen.SelectFile(*I,"") == false)
1411          return _error->Error("Problem with SelectFile");
1412          
1413       if (Gen.MergeList(Parser) == false)
1414          return _error->Error("Problem with MergeList");
1415    }
1416
1417    Progress.Done();
1418    GCache = &Gen.GetCache();
1419    Stats(CmdL);
1420    
1421    return true;
1422 #endif   
1423 }
1424                                                                         /*}}}*/
1425 // DisplayRecord - Displays the complete record for the package         /*{{{*/
1426 // ---------------------------------------------------------------------
1427 /* This displays the package record from the proper package index file. 
1428    It is not used by DumpAvail for performance reasons. */
1429 bool DisplayRecord(pkgCache::VerIterator V)
1430 {
1431    // Find an appropriate file
1432    pkgCache::VerFileIterator Vf = V.FileList();
1433    for (; Vf.end() == false; Vf++)
1434       if ((Vf.File()->Flags & pkgCache::Flag::NotSource) == 0)
1435          break;
1436    if (Vf.end() == true)
1437       Vf = V.FileList();
1438       
1439 // CNC:2002-07-24
1440 #if HAVE_RPM
1441    pkgRecords Recs(*GCache);
1442    pkgRecords::Parser &P = Recs.Lookup(Vf);
1443    const char *Start;
1444    const char *End;
1445    P.GetRec(Start,End);
1446    fwrite(Start,End-Start,1,stdout);
1447    putc('\n',stdout);
1448 #else
1449    // Check and load the package list file
1450    pkgCache::PkgFileIterator I = Vf.File();
1451    if (I.IsOk() == false)
1452       return _error->Error(_("Package file %s is out of sync."),I.FileName());
1453    
1454    FileFd PkgF(I.FileName(),FileFd::ReadOnly);
1455    if (_error->PendingError() == true)
1456       return false;
1457    
1458    // Read the record and then write it out again.
1459    unsigned char *Buffer = new unsigned char[GCache->HeaderP->MaxVerFileSize+1];
1460    Buffer[V.FileList()->Size] = '\n';
1461    if (PkgF.Seek(V.FileList()->Offset) == false ||
1462        PkgF.Read(Buffer,V.FileList()->Size) == false ||
1463        fwrite(Buffer,1,V.FileList()->Size+1,stdout) < V.FileList()->Size+1)
1464    {
1465       delete [] Buffer;
1466       return false;
1467    }
1468    
1469    delete [] Buffer;
1470 #endif
1471
1472    return true;
1473 }
1474                                                                         /*}}}*/
1475 // Search - Perform a search                                            /*{{{*/
1476 // ---------------------------------------------------------------------
1477 /* This searches the package names and pacakge descriptions for a pattern */
1478 struct ExVerFile
1479 {
1480    pkgCache::VerFile *Vf;
1481    bool NameMatch;
1482 };
1483
1484 bool Search(CommandLine &CmdL)
1485 {
1486    pkgCache &Cache = *GCache;
1487    bool ShowFull = _config->FindB("APT::Cache::ShowFull",false);
1488    bool NamesOnly = _config->FindB("APT::Cache::NamesOnly",false);
1489    unsigned NumPatterns = CmdL.FileSize() -1;
1490    
1491    pkgDepCache::Policy Plcy;
1492    
1493    // Make sure there is at least one argument
1494    if (NumPatterns < 1)
1495       return _error->Error(_("You must give exactly one pattern"));
1496    
1497    // Compile the regex pattern
1498    regex_t *Patterns = new regex_t[NumPatterns];
1499    memset(Patterns,0,sizeof(*Patterns)*NumPatterns);
1500    for (unsigned I = 0; I != NumPatterns; I++)
1501    {
1502       if (regcomp(&Patterns[I],CmdL.FileList[I+1],REG_EXTENDED | REG_ICASE | 
1503                   REG_NOSUB) != 0)
1504       {
1505          for (; I != 0; I--)
1506             regfree(&Patterns[I]);
1507          return _error->Error("Regex compilation error");
1508       }      
1509    }
1510    
1511    // Create the text record parser
1512    pkgRecords Recs(Cache);
1513    if (_error->PendingError() == true)
1514    {
1515       for (unsigned I = 0; I != NumPatterns; I++)
1516          regfree(&Patterns[I]);
1517       return false;
1518    }
1519    
1520    ExVerFile *VFList = new ExVerFile[Cache.HeaderP->PackageCount+1];
1521    memset(VFList,0,sizeof(*VFList)*Cache.HeaderP->PackageCount+1);
1522
1523    // Map versions that we want to write out onto the VerList array.
1524    for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
1525    {
1526       VFList[P->ID].NameMatch = NumPatterns != 0;
1527       for (unsigned I = 0; I != NumPatterns; I++)
1528       {
1529          if (regexec(&Patterns[I],P.Name(),0,0,0) == 0)
1530             VFList[P->ID].NameMatch &= true;
1531          else
1532             VFList[P->ID].NameMatch = false;
1533       }
1534         
1535       // Doing names only, drop any that dont match..
1536       if (NamesOnly == true && VFList[P->ID].NameMatch == false)
1537          continue;
1538          
1539       // Find the proper version to use. 
1540       pkgCache::VerIterator V = Plcy.GetCandidateVer(P);
1541       if (V.end() == false)
1542          VFList[P->ID].Vf = V.FileList();
1543    }
1544       
1545    // Include all the packages that provide matching names too
1546    for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
1547    {
1548       if (VFList[P->ID].NameMatch == false)
1549          continue;
1550
1551       for (pkgCache::PrvIterator Prv = P.ProvidesList() ; Prv.end() == false; Prv++)
1552       {
1553          pkgCache::VerIterator V = Plcy.GetCandidateVer(Prv.OwnerPkg());
1554          if (V.end() == false)
1555          {
1556             VFList[Prv.OwnerPkg()->ID].Vf = V.FileList();
1557             VFList[Prv.OwnerPkg()->ID].NameMatch = true;
1558          }
1559       }
1560    }
1561
1562    LocalitySort(&VFList->Vf,Cache.HeaderP->PackageCount,sizeof(*VFList));
1563
1564    // Iterate over all the version records and check them
1565    for (ExVerFile *J = VFList; J->Vf != 0; J++)
1566    {
1567       pkgRecords::Parser &P = Recs.Lookup(pkgCache::VerFileIterator(Cache,J->Vf));
1568
1569       bool Match = true;
1570       if (J->NameMatch == false)
1571       {
1572          string LongDesc = P.LongDesc(); 
1573          // CNC 2004-04-10
1574          string ShortDesc = P.ShortDesc();
1575          Match = NumPatterns != 0;
1576          for (unsigned I = 0; I != NumPatterns; I++)
1577          {
1578             if (regexec(&Patterns[I],LongDesc.c_str(),0,0,0) == 0 ||
1579                 regexec(&Patterns[I],ShortDesc.c_str(),0,0,0) == 0)
1580                Match &= true;
1581             else
1582                Match = false;
1583          }
1584       }
1585       
1586       if (Match == true)
1587       {
1588          if (ShowFull == true)
1589          {
1590             const char *Start;
1591             const char *End;
1592             P.GetRec(Start,End);
1593             fwrite(Start,End-Start,1,stdout);
1594             putc('\n',stdout);
1595          }       
1596          else
1597             printf("%s - %s\n",P.Name().c_str(),P.ShortDesc().c_str());
1598       }
1599    }
1600    
1601    delete [] VFList;
1602    for (unsigned I = 0; I != NumPatterns; I++)
1603       regfree(&Patterns[I]);
1604    if (ferror(stdout))
1605        return _error->Error("Write to stdout failed");
1606    return true;
1607 }
1608                                                                         /*}}}*/
1609 // ShowPackage - Dump the package record to the screen                  /*{{{*/
1610 // ---------------------------------------------------------------------
1611 /* */
1612 bool ShowPackage(CommandLine &CmdL)
1613 {   
1614    pkgCache &Cache = *GCache;
1615    pkgDepCache::Policy Plcy;
1616
1617    unsigned found = 0;
1618    
1619    for (const char **I = CmdL.FileList + 1; *I != 0; I++)
1620    {
1621       pkgCache::PkgIterator Pkg = Cache.FindPkg(*I);
1622       if (Pkg.end() == true)
1623       {
1624          _error->Warning(_("Unable to locate package %s"),*I);
1625          continue;
1626       }
1627
1628       ++found;
1629
1630       // CNC:2004-07-09
1631       // If it's a virtual package, require user to select similarly to apt-get
1632       if (Pkg.VersionList().end() == true and Pkg->ProvidesList != 0)
1633       {
1634          ioprintf(cout, _("Package %s is a virtual package provided by:\n"),
1635                   Pkg.Name());
1636          for (pkgCache::PrvIterator Prv = Pkg.ProvidesList();
1637              Prv.end() == false; Prv++)
1638          {
1639             pkgCache::VerIterator V = Plcy.GetCandidateVer(Prv.OwnerPkg());
1640             if (V.end() == true)
1641                continue;
1642             if (V != Prv.OwnerVer())
1643                continue;
1644             cout << "  " << Prv.OwnerPkg().Name() << " " << V.VerStr() << endl;
1645          }
1646          cout << _("You should explicitly select one to show.") << endl;
1647          _error->Error(_("Package %s is a virtual package with multiple providers."), Pkg.Name());
1648          return false;
1649       }
1650
1651       // Find the proper version to use.
1652       if (_config->FindB("APT::Cache::AllVersions","true") == true)
1653       {
1654          pkgCache::VerIterator V;
1655          for (V = Pkg.VersionList(); V.end() == false; V++)
1656          {
1657             if (DisplayRecord(V) == false)
1658                return false;
1659          }
1660       }
1661       else
1662       {
1663          pkgCache::VerIterator V = Plcy.GetCandidateVer(Pkg);
1664          if (V.end() == true || V.FileList().end() == true)
1665             continue;
1666          if (DisplayRecord(V) == false)
1667             return false;
1668       }      
1669    }
1670
1671    if (found > 0)
1672         return true;
1673    return _error->Error(_("No packages found"));
1674 }
1675                                                                         /*}}}*/
1676 // ShowPkgNames - Show package names                                    /*{{{*/
1677 // ---------------------------------------------------------------------
1678 /* This does a prefix match on the first argument */
1679 bool ShowPkgNames(CommandLine &CmdL)
1680 {
1681    pkgCache &Cache = *GCache;
1682    pkgCache::PkgIterator I = Cache.PkgBegin();
1683    bool All = _config->FindB("APT::Cache::AllNames","false");
1684    
1685    if (CmdL.FileList[1] != 0)
1686    {
1687       for (;I.end() != true; I++)
1688       {
1689          if (All == false && I->VersionList == 0)
1690             continue;
1691          
1692          if (strncmp(I.Name(),CmdL.FileList[1],strlen(CmdL.FileList[1])) == 0)
1693             cout << I.Name() << endl;
1694       }
1695
1696       return true;
1697    }
1698    
1699    // Show all pkgs
1700    for (;I.end() != true; I++)
1701    {
1702       if (All == false && I->VersionList == 0)
1703          continue;
1704       cout << I.Name() << endl;
1705    }
1706    
1707    return true;
1708 }
1709                                                                         /*}}}*/
1710 // ShowSrcPackage - Show source package records                         /*{{{*/
1711 // ---------------------------------------------------------------------
1712 /* */
1713 bool ShowSrcPackage(CommandLine &CmdL)
1714 {
1715    pkgSourceList List;
1716    List.ReadMainList();
1717    
1718    // Create the text record parsers
1719    pkgSrcRecords SrcRecs(List);
1720    if (_error->PendingError() == true)
1721       return false;
1722
1723    for (const char **I = CmdL.FileList + 1; *I != 0; I++)
1724    {
1725       SrcRecs.Restart();
1726       
1727       pkgSrcRecords::Parser *Parse;
1728       while ((Parse = SrcRecs.Find(*I,false)) != 0)
1729          cout << Parse->AsStr() << endl;;
1730    }      
1731    return true;
1732 }
1733                                                                         /*}}}*/
1734 // Policy - Show the results of the preferences file                    /*{{{*/
1735 // ---------------------------------------------------------------------
1736 /* */
1737 bool Policy(CommandLine &CmdL)
1738 {
1739    if (SrcList == 0)
1740       return _error->Error("Generate must be enabled for this function");
1741    
1742    pkgCache &Cache = *GCache;
1743    pkgPolicy Plcy(&Cache);
1744    if (ReadPinFile(Plcy) == false)
1745       return false;
1746    
1747    // Print out all of the package files
1748    if (CmdL.FileList[1] == 0)
1749    {
1750       cout << _("Package Files:") << endl;   
1751       for (pkgCache::PkgFileIterator F = Cache.FileBegin(); F.end() == false; F++)
1752       {
1753          // Locate the associated index files so we can derive a description
1754          pkgIndexFile *Indx;
1755          if (SrcList->FindIndex(F,Indx) == false &&
1756              _system->FindIndex(F,Indx) == false)
1757             return _error->Error(_("Cache is out of sync, can't x-ref a package file"));
1758          printf(_("%4i %s\n"),
1759                 Plcy.GetPriority(F),Indx->Describe(true).c_str());
1760          
1761          // Print the reference information for the package
1762          string Str = F.RelStr();
1763          if (Str.empty() == false)
1764             printf("     release %s\n",F.RelStr().c_str());
1765          if (F.Site() != 0 && F.Site()[0] != 0)
1766             printf("     origin %s\n",F.Site());
1767       }
1768       
1769       // Show any packages have explicit pins
1770       cout << _("Pinned Packages:") << endl;
1771       pkgCache::PkgIterator I = Cache.PkgBegin();
1772       for (;I.end() != true; I++)
1773       {
1774          if (Plcy.GetPriority(I) == 0)
1775             continue;
1776
1777          // Print the package name and the version we are forcing to
1778          cout << "     " << I.Name() << " -> ";
1779          
1780          pkgCache::VerIterator V = Plcy.GetMatch(I);
1781          if (V.end() == true)
1782             cout << _("(not found)") << endl;
1783          else
1784             cout << V.VerStr() << endl;
1785       }     
1786       
1787       return true;
1788    }
1789    
1790    // Print out detailed information for each package
1791    for (const char **I = CmdL.FileList + 1; *I != 0; I++)
1792    {
1793       pkgCache::PkgIterator Pkg = Cache.FindPkg(*I);
1794       if (Pkg.end() == true)
1795       {
1796          _error->Warning(_("Unable to locate package %s"),*I);
1797          continue;
1798       }
1799       
1800       cout << Pkg.Name() << ":" << endl;
1801       
1802       // Installed version
1803       cout << _("  Installed: ");
1804       if (Pkg->CurrentVer == 0)
1805          cout << _("(none)") << endl;
1806       else
1807          cout << Pkg.CurrentVer().VerStr() << endl;
1808       
1809       // Candidate Version 
1810       cout << _("  Candidate: ");
1811       pkgCache::VerIterator V = Plcy.GetCandidateVer(Pkg);
1812       if (V.end() == true)
1813          cout << _("(none)") << endl;
1814       else
1815          cout << V.VerStr() << endl;
1816
1817       // Pinned version
1818       if (Plcy.GetPriority(Pkg) != 0)
1819       {
1820          cout << _("  Package Pin: ");
1821          V = Plcy.GetMatch(Pkg);
1822          if (V.end() == true)
1823             cout << _("(not found)") << endl;
1824          else
1825             cout << V.VerStr() << endl;
1826       }
1827       
1828       // Show the priority tables
1829       cout << _("  Version Table:") << endl;
1830       for (V = Pkg.VersionList(); V.end() == false; V++)
1831       {
1832          if (Pkg.CurrentVer() == V)
1833             cout << " *** " << V.VerStr();
1834          else
1835             cout << "     " << V.VerStr();
1836          // CNC:2004-05-29
1837          if (Plcy.GetCandidateVer(Pkg) == V)
1838             cout << " " << Plcy.GetPriority(Pkg) << endl;
1839          else
1840             cout << " 0" << endl;
1841          for (pkgCache::VerFileIterator VF = V.FileList(); VF.end() == false; VF++)
1842          {
1843             // Locate the associated index files so we can derive a description
1844             pkgIndexFile *Indx;
1845             if (SrcList->FindIndex(VF.File(),Indx) == false &&
1846                 _system->FindIndex(VF.File(),Indx) == false)
1847                return _error->Error(_("Cache is out of sync, can't x-ref a package file"));
1848             printf(_("       %4i %s\n"),Plcy.GetPriority(VF.File()),
1849                    Indx->Describe(true).c_str());
1850          }       
1851       }      
1852    }
1853    
1854    return true;
1855 }
1856                                                                         /*}}}*/
1857 // GenCaches - Call the main cache generator                            /*{{{*/
1858 // ---------------------------------------------------------------------
1859 /* */
1860 bool GenCaches(CommandLine &Cmd)
1861 {
1862    OpTextProgress Progress(*_config);
1863    
1864    pkgSourceList List;
1865    if (List.ReadMainList() == false)
1866       return false;   
1867    return pkgMakeStatusCache(List,Progress);
1868 }
1869                                                                         /*}}}*/
1870 // ShowHelp - Show a help screen                                        /*{{{*/
1871 // ---------------------------------------------------------------------
1872 /* */
1873 bool ShowHelp(CommandLine &Cmd)
1874 {
1875    ioprintf(cout,_("%s %s for %s %s compiled on %s %s\n"),PACKAGE,VERSION,
1876             COMMON_OS,COMMON_CPU,__DATE__,__TIME__);
1877    
1878    if (_config->FindB("version") == true)
1879      return true;
1880
1881    cout << 
1882     _("Usage: apt-cache [options] command\n"
1883       "       apt-cache [options] add file1 [file2 ...]\n"
1884       "       apt-cache [options] showpkg pkg1 [pkg2 ...]\n"
1885       "       apt-cache [options] showsrc pkg1 [pkg2 ...]\n"
1886       "\n"
1887       "apt-cache is a low-level tool used to manipulate APT's binary\n"
1888       "cache files, and query information from them\n"
1889       "\n"
1890       "Commands:\n"
1891       "   add - Add a package file to the source cache\n"
1892       "   gencaches - Build both the package and source cache\n"
1893       "   showpkg - Show some general information for a single package\n"
1894       "   showsrc - Show source records\n"
1895       "   stats - Show some basic statistics\n"
1896       "   dump - Show the entire file in a terse form\n"
1897       "   dumpavail - Print an available file to stdout\n"
1898       "   unmet - Show unmet dependencies\n"
1899       "   search - Search the package list for a regex pattern\n"
1900       "   show - Show a readable record for the package\n"
1901       "   depends - Show raw dependency information for a package\n"
1902       "   whatdepends - Show raw dependency information on a package\n"
1903       // "   rdepends - Show reverse dependency information for a package\n"
1904       "   pkgnames - List the names of all packages\n"
1905       "   dotty - Generate package graphs for GraphVis\n"
1906       "   xvcg - Generate package graphs for xvcg\n"
1907       "   policy - Show policy settings\n"
1908 // CNC:2003-03-16
1909       );
1910 #ifdef WITH_LUA
1911       _lua->RunScripts("Scripts::AptCache::Help::Command");
1912 #endif
1913       cout << _(
1914       "\n"
1915       "Options:\n"
1916       "  -h   This help text.\n"
1917       "  -p=? The package cache.\n"
1918       "  -s=? The source cache.\n"
1919       "  -q   Disable progress indicator.\n"
1920       "  -i   Show only important deps for the unmet command.\n"
1921       "  -c=? Read this configuration file\n"
1922       "  -o=? Set an arbitary configuration option, eg -o dir::cache=/tmp\n"
1923       "See the apt-cache(8) and apt.conf(5) manual pages for more information.\n");
1924    return true;
1925 }
1926                                                                         /*}}}*/
1927 // CacheInitialize - Initialize things for apt-cache                    /*{{{*/
1928 // ---------------------------------------------------------------------
1929 /* */
1930 void CacheInitialize()
1931 {
1932    _config->Set("quiet",0);
1933    _config->Set("help",false);
1934 }
1935                                                                         /*}}}*/
1936
1937 int main(int argc,const char *argv[])
1938 {
1939    CommandLine::Args Args[] = {
1940       {'h',"help","help",0},
1941       {'v',"version","version",0},
1942       {'p',"pkg-cache","Dir::Cache::pkgcache",CommandLine::HasArg},
1943       {'s',"src-cache","Dir::Cache::srcpkgcache",CommandLine::HasArg},
1944       {'q',"quiet","quiet",CommandLine::IntLevel},
1945       {'i',"important","APT::Cache::Important",0},
1946       {'f',"full","APT::Cache::ShowFull",0},
1947       {'g',"generate","APT::Cache::Generate",0},
1948       {'a',"all-versions","APT::Cache::AllVersions",0},
1949       {0,"names-only","APT::Cache::NamesOnly",0},
1950       {'n',"all-names","APT::Cache::AllNames",0},
1951       {0,"recurse","APT::Cache::RecurseDepends",0},
1952       {'c',"config-file",0,CommandLine::ConfigFile},
1953       {'o',"option",0,CommandLine::ArbItem},
1954       {'n',"installed","APT::Cache::Installed",0},
1955       {0,0,0,0}};
1956    CommandLine::Dispatch CmdsA[] = {{"help",&ShowHelp},
1957                                     {"add",&DoAdd},
1958                                     {"gencaches",&GenCaches},
1959                                     {"showsrc",&ShowSrcPackage},
1960                                     {0,0}};
1961    CommandLine::Dispatch CmdsB[] = {{"showpkg",&DumpPackage},
1962                                     {"stats",&Stats},
1963                                     {"dump",&Dump},
1964                                     {"dumpavail",&DumpAvail},
1965                                     {"unmet",&UnMet},
1966                                     {"search",&Search},
1967                                     {"depends",&Depends},
1968                                     {"whatdepends",&WhatDepends},
1969                                     {"rdepends",&RDepends},
1970                                     {"dotty",&Dotty},
1971                                     {"xvcg",&XVcg},
1972                                     {"show",&ShowPackage},
1973                                     {"pkgnames",&ShowPkgNames},
1974                                     {"policy",&Policy},
1975 // CNC:2003-11-23
1976 #ifdef WITH_LUA
1977                                     {"script",&Script},
1978 #endif
1979                                     {0,0}};
1980
1981    CacheInitialize();
1982
1983    // Set up gettext support
1984    setlocale(LC_ALL,"");
1985    textdomain(PACKAGE);
1986
1987    // Parse the command line and initialize the package library
1988    CommandLine CmdL(Args,_config);
1989    if (pkgInitConfig(*_config) == false ||
1990        CmdL.Parse(argc,argv) == false ||
1991        pkgInitSystem(*_config,_system) == false)
1992    {
1993       _error->DumpErrors();
1994       return 100;
1995    }
1996
1997    // See if the help should be shown
1998    if (_config->FindB("help") == true ||
1999        CmdL.FileSize() == 0)
2000    {
2001       ShowHelp(CmdL);
2002       return 0;
2003    }
2004    
2005    // Deal with stdout not being a tty
2006    if (ttyname(STDOUT_FILENO) == 0 && _config->FindI("quiet",0) < 1)
2007       _config->Set("quiet","1");
2008
2009    // CNC:2004-02-18
2010    if (_system->LockRead() == false)
2011    {
2012       bool Errors = _error->PendingError();
2013       _error->DumpErrors();
2014       return Errors == true?100:0;
2015    }
2016
2017    if (CmdL.DispatchArg(CmdsA,false) == false && _error->PendingError() == false)
2018    { 
2019       MMap *Map = 0;
2020       if (_config->FindB("APT::Cache::Generate",true) == false)
2021       {
2022          Map = new MMap(*new FileFd(_config->FindFile("Dir::Cache::pkgcache"),
2023                                     FileFd::ReadOnly),MMap::Public|MMap::ReadOnly);
2024       }
2025       else
2026       {
2027          // Open the cache file
2028          SrcList = new pkgSourceList;
2029          SrcList->ReadMainList();
2030
2031          // Generate it and map it
2032          OpProgress Prog;
2033          pkgMakeStatusCache(*SrcList,Prog,&Map,true);
2034       }
2035       
2036       if (_error->PendingError() == false)
2037       {
2038          pkgCache Cache(Map);   
2039          GCache = &Cache;
2040 // CNC:2003-11-23
2041 #ifdef WITH_LUA
2042          _lua->SetCache(&Cache);
2043          double Consume = 0;
2044          if (argc > 1 && _error->PendingError() == false &&
2045              _lua->HasScripts("Scripts::AptCache::Command") == true)
2046          {
2047             _lua->SetGlobal("command_args", CmdL.FileList);
2048             _lua->SetGlobal("command_consume", 0.0);
2049             _lua->RunScripts("Scripts::AptCache::Command");
2050             Consume = _lua->GetGlobalNum("command_consume");
2051             _lua->ResetGlobals();
2052             _lua->ResetCaches();
2053          }
2054
2055          if (Consume == 0)
2056 #endif
2057          if (_error->PendingError() == false)
2058             CmdL.DispatchArg(CmdsB);
2059       }
2060       delete Map;
2061    }
2062    
2063    // Print any errors or warnings found during parsing
2064    if (_error->empty() == false)
2065    {
2066       bool Errors = _error->PendingError();
2067       _error->DumpErrors();
2068       return Errors == true?100:0;
2069    }
2070           
2071    return 0;
2072 }
2073
2074 // vim:sts=3:sw=3