- move common code in apt-cache/shell to cmdline
[apt.git] / cmdline / apt-cache.cc
1 // -*- mode: c++; 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 #include "cmdline.h"
47                                                                         /*}}}*/
48
49 using namespace std;
50
51 pkgCache *GCache = 0;
52 pkgSourceList *SrcList = 0;
53
54 // CNC:2003-11-23
55 // Script - Scripting stuff.                                            /*{{{*/
56 // ---------------------------------------------------------------------
57 /* */
58 #ifdef WITH_LUA
59 bool Script(CommandLine &CmdL)
60 {
61    for (const char **I = CmdL.FileList+1; *I != 0; I++)
62       _config->Set("Scripts::AptCache::Script::", *I);
63
64    _lua->SetCache(GCache);
65    _lua->RunScripts("Scripts::AptCache::Script");
66    _lua->ResetGlobals();
67
68    return true;
69 }
70 #endif
71                                                                         /*}}}*/
72 // UnMet - Show unmet dependencies                                      /*{{{*/
73 // ---------------------------------------------------------------------
74 /* */
75 bool UnMet(CommandLine &CmdL)
76 {
77    return cmdUnMet(CmdL, *GCache);
78 }
79                                                                         /*}}}*/
80 // DumpPackage - Show a dump of a package record                        /*{{{*/
81 // ---------------------------------------------------------------------
82 /* */
83 bool DumpPackage(CommandLine &CmdL)
84 {   
85    return cmdDumpPackage(CmdL, *GCache);
86 }
87                                                                         /*}}}*/
88 // Stats - Dump some nice statistics                                    /*{{{*/
89 // ---------------------------------------------------------------------
90 /* */
91 bool Stats(CommandLine &Cmd)
92 {
93    pkgCache &Cache = *GCache;
94    cout << _("Total Package Names : ") << Cache.Head().PackageCount << " (" <<
95       SizeToStr(Cache.Head().PackageCount*Cache.Head().PackageSz) << ')' << endl;
96
97    int Normal = 0;
98    int Virtual = 0;
99    int NVirt = 0;
100    int DVirt = 0;
101    int Missing = 0;
102    pkgCache::PkgIterator I = Cache.PkgBegin();
103    for (;I.end() != true; I++)
104    {
105       if (I->VersionList != 0 && I->ProvidesList == 0)
106       {
107          Normal++;
108          continue;
109       }
110
111       if (I->VersionList != 0 && I->ProvidesList != 0)
112       {
113          NVirt++;
114          continue;
115       }
116       
117       if (I->VersionList == 0 && I->ProvidesList != 0)
118       {
119          // Only 1 provides
120          if (I.ProvidesList()->NextProvides == 0)
121          {
122             DVirt++;
123          }
124          else
125             Virtual++;
126          continue;
127       }
128       if (I->VersionList == 0 && I->ProvidesList == 0)
129       {
130          Missing++;
131          continue;
132       }
133    }
134    cout << _("  Normal Packages: ") << Normal << endl;
135    cout << _("  Pure Virtual Packages: ") << Virtual << endl;
136    cout << _("  Single Virtual Packages: ") << DVirt << endl;
137    cout << _("  Mixed Virtual Packages: ") << NVirt << endl;
138    cout << _("  Missing: ") << Missing << endl;
139    
140    cout << _("Total Distinct Versions: ") << Cache.Head().VersionCount << " (" <<
141       SizeToStr(Cache.Head().VersionCount*Cache.Head().VersionSz) << ')' << endl;
142    cout << _("Total Dependencies: ") << Cache.Head().DependsCount << " (" << 
143       SizeToStr(Cache.Head().DependsCount*Cache.Head().DependencySz) << ')' << endl;
144    
145    cout << _("Total Ver/File relations: ") << Cache.Head().VerFileCount << " (" <<
146       SizeToStr(Cache.Head().VerFileCount*Cache.Head().VerFileSz) << ')' << endl;
147    cout << _("Total Provides Mappings: ") << Cache.Head().ProvidesCount << " (" <<
148       SizeToStr(Cache.Head().ProvidesCount*Cache.Head().ProvidesSz) << ')' << endl;
149    
150    // String list stats
151    size_t Size = 0;
152    unsigned long Count = 0;
153    for (pkgCache::StringItem *I = Cache.StringItemP + Cache.Head().StringList;
154         I!= Cache.StringItemP; I = Cache.StringItemP + I->NextItem)
155    {
156       Count++;
157       Size += strlen(Cache.StrP + I->String) + 1;
158    }
159    cout << _("Total Globbed Strings: ") << Count << " (" << SizeToStr(Size) << ')' << endl;
160
161    size_t DepVerSize = 0;
162    for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
163    {
164       for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; V++)
165       {
166          for (pkgCache::DepIterator D = V.DependsList(); D.end() == false; D++)
167          {
168             if (D->Version != 0)
169                DepVerSize += strlen(D.TargetVer()) + 1;
170          }
171       }
172    }
173    cout << _("Total Dependency Version space: ") << SizeToStr(DepVerSize) << endl;
174    
175    unsigned long Slack = 0;
176    for (int I = 0; I != 7; I++)
177       Slack += Cache.Head().Pools[I].ItemSize*Cache.Head().Pools[I].Count;
178    cout << _("Total Slack space: ") << SizeToStr(Slack) << endl;
179    
180    unsigned long Total = 0;
181    Total = Slack + Size + Cache.Head().DependsCount*Cache.Head().DependencySz + 
182            Cache.Head().VersionCount*Cache.Head().VersionSz +
183            Cache.Head().PackageCount*Cache.Head().PackageSz + 
184            Cache.Head().VerFileCount*Cache.Head().VerFileSz +
185            Cache.Head().ProvidesCount*Cache.Head().ProvidesSz;
186    cout << _("Total Space Accounted for: ") << SizeToStr(Total) << endl;
187    
188    return true;
189 }
190                                                                         /*}}}*/
191 // Dump - show everything                                               /*{{{*/
192 // ---------------------------------------------------------------------
193 /* This is worthless except fer debugging things */
194 bool Dump(CommandLine &Cmd)
195 {
196    pkgCache &Cache = *GCache;
197    cout << "Using Versioning System: " << Cache.VS->Label << endl;
198    
199    for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
200    {
201       cout << "Package: " << P.Name() << endl;
202       for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; V++)
203       {
204          cout << " Version: " << V.VerStr() << endl;
205          cout << "     File: " << V.FileList().File().FileName() << endl;
206          for (pkgCache::DepIterator D = V.DependsList(); D.end() == false; D++)
207             cout << "  Depends: " << D.TargetPkg().Name() << ' ' << 
208                              DeNull(D.TargetVer()) << endl;
209       }      
210    }
211
212    for (pkgCache::PkgFileIterator F = Cache.FileBegin(); F.end() == false; F++)
213    {
214       cout << "File: " << F.FileName() << endl;
215       cout << " Type: " << F.IndexType() << endl;
216       cout << " Size: " << F->Size << endl;
217       cout << " ID: " << F->ID << endl;
218       cout << " Flags: " << F->Flags << endl;
219       cout << " Time: " << TimeRFC1123(F->mtime) << endl;
220       cout << " Archive: " << DeNull(F.Archive()) << endl;
221       cout << " Component: " << DeNull(F.Component()) << endl;
222       cout << " Version: " << DeNull(F.Version()) << endl;
223       cout << " Origin: " << DeNull(F.Origin()) << endl;
224       cout << " Site: " << DeNull(F.Site()) << endl;
225       cout << " Label: " << DeNull(F.Label()) << endl;
226       cout << " Architecture: " << DeNull(F.Architecture()) << endl;
227    }
228
229    return true;
230 }
231                                                                         /*}}}*/
232 // DumpAvail - Print out the available list                             /*{{{*/
233 // ---------------------------------------------------------------------
234 /* This is needed to make dpkg --merge happy.. I spent a bit of time to 
235    make this run really fast, perhaps I went a little overboard.. */
236 bool DumpAvail(CommandLine &Cmd)
237 {
238    pkgCache &Cache = *GCache;
239
240    pkgPolicy Plcy(&Cache);
241    if (ReadPinFile(Plcy) == false)
242       return false;
243    
244    unsigned long Count = Cache.HeaderP->PackageCount+1;
245    pkgCache::VerFile **VFList = new pkgCache::VerFile *[Count];
246    memset(VFList,0,sizeof(*VFList)*Count);
247    
248    // Map versions that we want to write out onto the VerList array.
249    for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
250    {    
251       if (P->VersionList == 0)
252          continue;
253       
254       /* Find the proper version to use. If the policy says there are no
255          possible selections we return the installed version, if available..
256          This prevents dselect from making it obsolete. */
257       pkgCache::VerIterator V = Plcy.GetCandidateVer(P);
258       if (V.end() == true)
259       {
260          if (P->CurrentVer == 0)
261             continue;
262          V = P.CurrentVer();
263       }
264       
265       pkgCache::VerFileIterator VF = V.FileList();
266       for (; VF.end() == false ; VF++)
267          if ((VF.File()->Flags & pkgCache::Flag::NotSource) == 0)
268             break;
269       
270       /* Okay, here we have a bit of a problem.. The policy has selected the
271          currently installed package - however it only exists in the
272          status file.. We need to write out something or dselect will mark
273          the package as obsolete! Thus we emit the status file entry, but
274          below we remove the status line to make it valid for the 
275          available file. However! We only do this if their do exist *any*
276          non-source versions of the package - that way the dselect obsolete
277          handling works OK. */
278       if (VF.end() == true)
279       {
280          for (pkgCache::VerIterator Cur = P.VersionList(); Cur.end() != true; Cur++)
281          {
282             for (VF = Cur.FileList(); VF.end() == false; VF++)
283             {    
284                if ((VF.File()->Flags & pkgCache::Flag::NotSource) == 0)
285                {
286                   VF = V.FileList();
287                   break;
288                }
289             }
290             
291             if (VF.end() == false)
292                break;
293          }
294       }
295       
296 // CNC:2002-07-24
297 #if HAVE_RPM
298       if (VF.end() == false)
299       {
300          pkgRecords Recs(Cache);
301          pkgRecords::Parser &P = Recs.Lookup(VF);
302          const char *Start;
303          const char *End;
304          P.GetRec(Start,End);
305          cout << string(Start,End-Start) << endl;
306       }
307    }
308    return !_error->PendingError();
309 #else
310       VFList[P->ID] = VF;
311    }
312 #endif
313    
314    LocalitySort(VFList,Count,sizeof(*VFList));
315
316    // Iterate over all the package files and write them out.
317    char *Buffer = new char[Cache.HeaderP->MaxVerFileSize+10];
318    for (pkgCache::VerFile **J = VFList; *J != 0;)
319    {
320       pkgCache::PkgFileIterator File(Cache,(*J)->File + Cache.PkgFileP);
321       if (File.IsOk() == false)
322       {
323          _error->Error(_("Package file %s is out of sync."),File.FileName());
324          break;
325       }
326
327       FileFd PkgF(File.FileName(),FileFd::ReadOnly);
328       if (_error->PendingError() == true)
329          break;
330       
331       /* Write all of the records from this package file, since we
332          already did locality sorting we can now just seek through the
333          file in read order. We apply 1 more optimization here, since often
334          there will be < 1 byte gaps between records (for the \n) we read that
335          into the next buffer and offset a bit.. */
336       unsigned long Pos = 0;
337       for (; *J != 0; J++)
338       {
339          if ((*J)->File + Cache.PkgFileP != File)
340             break;
341          
342          const pkgCache::VerFile &VF = **J;
343
344          // Read the record and then write it out again.
345          unsigned long Jitter = VF.Offset - Pos;
346          if (Jitter > 8)
347          {
348             if (PkgF.Seek(VF.Offset) == false)
349                break;
350             Jitter = 0;
351          }
352          
353          if (PkgF.Read(Buffer,VF.Size + Jitter) == false)
354             break;
355          Buffer[VF.Size + Jitter] = '\n';
356          
357          // See above..
358          if ((File->Flags & pkgCache::Flag::NotSource) == pkgCache::Flag::NotSource)
359          {
360             pkgTagSection Tags;
361             TFRewriteData RW[] = {{"Status",0,0},{"Config-Version",0,0},{0,0,0}};
362             const char *Zero = 0;
363             if (Tags.Scan(Buffer+Jitter,VF.Size+1) == false ||
364                 TFRewrite(stdout,Tags,&Zero,RW) == false)
365             {
366                _error->Error("Internal Error, Unable to parse a package record");
367                break;
368             }
369             fputc('\n',stdout);
370          }
371          else
372          {
373             if (fwrite(Buffer+Jitter,VF.Size+1,1,stdout) != 1)
374                break;
375          }
376          
377          Pos = VF.Offset + VF.Size;
378       }
379
380       fflush(stdout);
381       if (_error->PendingError() == true)
382          break;
383    }
384    
385    delete [] Buffer;
386    delete [] VFList;
387    return !_error->PendingError();
388 }
389                                                                         /*}}}*/
390 bool Depends(CommandLine &CmdL)
391 {
392    return cmdDepends(CmdL, *GCache);
393 }
394
395 bool RDepends(CommandLine &CmdL)
396 {
397    return cmdRDepends(CmdL, *GCache);
398 }
399
400 bool WhatDepends(CommandLine &CmdL)
401 {
402    return cmdWhatDepends(CmdL, *GCache);
403 }
404
405 bool WhatProvides(CommandLine &CmdL)
406 {
407    return cmdWhatProvides(CmdL, *GCache);
408 }
409
410 // xvcg - Generate a graph for xvcg                                     /*{{{*/
411 // ---------------------------------------------------------------------
412 // Code contributed from Junichi Uekawa <dancer@debian.org> on 20 June 2002.
413
414 bool XVcg(CommandLine &CmdL)
415 {
416    pkgCache &Cache = *GCache;
417    bool GivenOnly = _config->FindB("APT::Cache::GivenOnly",false);
418    
419    /* Normal packages are boxes
420       Pure Provides are triangles
421       Mixed are diamonds
422       rhomb are missing packages*/
423    const char *Shapes[] = {"ellipse","triangle","box","rhomb"};
424    
425    /* Initialize the list of packages to show.
426       1 = To Show
427       2 = To Show no recurse
428       3 = Emitted no recurse
429       4 = Emitted
430       0 = None */
431    enum States {None=0, ToShow, ToShowNR, DoneNR, Done};
432    enum TheFlags {ForceNR=(1<<0)};
433    unsigned char *Show = new unsigned char[Cache.Head().PackageCount];
434    unsigned char *Flags = new unsigned char[Cache.Head().PackageCount];
435    unsigned char *ShapeMap = new unsigned char[Cache.Head().PackageCount];
436    
437    // Show everything if no arguments given
438    if (CmdL.FileList[1] == 0)
439       for (unsigned long I = 0; I != Cache.Head().PackageCount; I++)
440          Show[I] = ToShow;
441    else
442       for (unsigned long I = 0; I != Cache.Head().PackageCount; I++)
443          Show[I] = None;
444    memset(Flags,0,sizeof(*Flags)*Cache.Head().PackageCount);
445    
446    // Map the shapes
447    for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++)
448    {   
449       if (Pkg->VersionList == 0)
450       {
451          // Missing
452          if (Pkg->ProvidesList == 0)
453             ShapeMap[Pkg->ID] = 0;
454          else
455             ShapeMap[Pkg->ID] = 1;
456       }
457       else
458       {
459          // Normal
460          if (Pkg->ProvidesList == 0)
461             ShapeMap[Pkg->ID] = 2;
462          else
463             ShapeMap[Pkg->ID] = 3;
464       }
465    }
466    
467    // Load the list of packages from the command line into the show list
468    for (const char **I = CmdL.FileList + 1; *I != 0; I++)
469    {
470       // Process per-package flags
471       string P = *I;
472       bool Force = false;
473       if (P.length() > 3)
474       {
475          if (P.end()[-1] == '^')
476          {
477             Force = true;
478             P.erase(P.end()-1);
479          }
480          
481          if (P.end()[-1] == ',')
482             P.erase(P.end()-1);
483       }
484       
485       // Locate the package
486       pkgCache::PkgIterator Pkg = Cache.FindPkg(P);
487       if (Pkg.end() == true)
488       {
489          _error->Warning(_("Unable to locate package %s"),*I);
490          continue;
491       }
492       Show[Pkg->ID] = ToShow;
493       
494       if (Force == true)
495          Flags[Pkg->ID] |= ForceNR;
496    }
497    
498    // Little header
499    cout << "graph: { title: \"packages\"" << endl <<
500      "xmax: 700 ymax: 700 x: 30 y: 30" << endl <<
501      "layout_downfactor: 8" << endl;
502
503    bool Act = true;
504    while (Act == true)
505    {
506       Act = false;
507       for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++)
508       {
509          // See we need to show this package
510          if (Show[Pkg->ID] == None || Show[Pkg->ID] >= DoneNR)
511             continue;
512
513          //printf ("node: { title: \"%s\" label: \"%s\" }\n", Pkg.Name(), Pkg.Name());
514          
515          // Colour as done
516          if (Show[Pkg->ID] == ToShowNR || (Flags[Pkg->ID] & ForceNR) == ForceNR)
517          {
518             // Pure Provides and missing packages have no deps!
519             if (ShapeMap[Pkg->ID] == 0 || ShapeMap[Pkg->ID] == 1)
520                Show[Pkg->ID] = Done;
521             else
522                Show[Pkg->ID] = DoneNR;
523          }       
524          else
525             Show[Pkg->ID] = Done;
526          Act = true;
527
528          // No deps to map out
529          if (Pkg->VersionList == 0 || Show[Pkg->ID] == DoneNR)
530             continue;
531          
532          pkgCache::VerIterator Ver = Pkg.VersionList();
533          for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; D++)
534          {
535             // See if anything can meet this dep
536             // Walk along the actual package providing versions
537             bool Hit = false;
538             pkgCache::PkgIterator DPkg = D.TargetPkg();
539             for (pkgCache::VerIterator I = DPkg.VersionList();
540                       I.end() == false && Hit == false; I++)
541             {
542                if (Cache.VS->CheckDep(I.VerStr(),D->CompareOp,D.TargetVer()) == true)
543                   Hit = true;
544             }
545             
546             // Follow all provides
547             for (pkgCache::PrvIterator I = DPkg.ProvidesList(); 
548                       I.end() == false && Hit == false; I++)
549             {
550                if (Cache.VS->CheckDep(I.ProvideVersion(),D->CompareOp,D.TargetVer()) == false)
551                   Hit = true;
552             }
553             
554
555             // Only graph critical deps     
556             if (D.IsCritical() == true)
557             {
558                printf ("edge: { sourcename: \"%s\" targetname: \"%s\" class: 2 ",Pkg.Name(), D.TargetPkg().Name() );
559                
560                // Colour the node for recursion
561                if (Show[D.TargetPkg()->ID] <= DoneNR)
562                {
563                   /* If a conflicts does not meet anything in the database
564                      then show the relation but do not recurse */
565                   if (Hit == false && 
566                       (D->Type == pkgCache::Dep::Conflicts ||
567                        D->Type == pkgCache::Dep::Obsoletes))
568                   {
569                      if (Show[D.TargetPkg()->ID] == None && 
570                          Show[D.TargetPkg()->ID] != ToShow)
571                         Show[D.TargetPkg()->ID] = ToShowNR;
572                   }               
573                   else
574                   {
575                      if (GivenOnly == true && Show[D.TargetPkg()->ID] != ToShow)
576                         Show[D.TargetPkg()->ID] = ToShowNR;
577                      else
578                         Show[D.TargetPkg()->ID] = ToShow;
579                   }
580                }
581                
582                // Edge colour
583                switch(D->Type)
584                {
585                   case pkgCache::Dep::Conflicts:
586                     printf("label: \"conflicts\" color: lightgreen }\n");
587                     break;
588                   case pkgCache::Dep::Obsoletes:
589                     printf("label: \"obsoletes\" color: lightgreen }\n");
590                     break;
591                   
592                   case pkgCache::Dep::PreDepends:
593                     printf("label: \"predepends\" color: blue }\n");
594                     break;
595                   
596                   default:
597                     printf("}\n");
598                   break;
599                }               
600             }       
601          }
602       }
603    }   
604    
605    /* Draw the box colours after the fact since we can not tell what colour
606       they should be until everything is finished drawing */
607    for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++)
608    {
609       if (Show[Pkg->ID] < DoneNR)
610          continue;
611
612       if (Show[Pkg->ID] == DoneNR)
613          printf("node: { title: \"%s\" label: \"%s\" color: orange shape: %s }\n", Pkg.Name(), Pkg.Name(),
614                 Shapes[ShapeMap[Pkg->ID]]);
615       else
616         printf("node: { title: \"%s\" label: \"%s\" shape: %s }\n", Pkg.Name(), Pkg.Name(), 
617                 Shapes[ShapeMap[Pkg->ID]]);
618       
619    }
620    
621    printf("}\n");
622    return true;
623 }
624                                                                         /*}}}*/
625
626
627 // Dotty - Generate a graph for Dotty                                   /*{{{*/
628 // ---------------------------------------------------------------------
629 /* Dotty is the graphvis program for generating graphs. It is a fairly
630    simple queuing algorithm that just writes dependencies and nodes. 
631    http://www.research.att.com/sw/tools/graphviz/ */
632 bool Dotty(CommandLine &CmdL)
633 {
634    pkgCache &Cache = *GCache;
635    bool GivenOnly = _config->FindB("APT::Cache::GivenOnly",false);
636    
637    /* Normal packages are boxes
638       Pure Provides are triangles
639       Mixed are diamonds
640       Hexagons are missing packages*/
641    const char *Shapes[] = {"hexagon","triangle","box","diamond"};
642    
643    /* Initialize the list of packages to show.
644       1 = To Show
645       2 = To Show no recurse
646       3 = Emitted no recurse
647       4 = Emitted
648       0 = None */
649    enum States {None=0, ToShow, ToShowNR, DoneNR, Done};
650    enum TheFlags {ForceNR=(1<<0)};
651    unsigned char *Show = new unsigned char[Cache.Head().PackageCount];
652    unsigned char *Flags = new unsigned char[Cache.Head().PackageCount];
653    unsigned char *ShapeMap = new unsigned char[Cache.Head().PackageCount];
654    
655    // Show everything if no arguments given
656    if (CmdL.FileList[1] == 0)
657       for (unsigned long I = 0; I != Cache.Head().PackageCount; I++)
658          Show[I] = ToShow;
659    else
660       for (unsigned long I = 0; I != Cache.Head().PackageCount; I++)
661          Show[I] = None;
662    memset(Flags,0,sizeof(*Flags)*Cache.Head().PackageCount);
663    
664    // Map the shapes
665    for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++)
666    {   
667       if (Pkg->VersionList == 0)
668       {
669          // Missing
670          if (Pkg->ProvidesList == 0)
671             ShapeMap[Pkg->ID] = 0;
672          else
673             ShapeMap[Pkg->ID] = 1;
674       }
675       else
676       {
677          // Normal
678          if (Pkg->ProvidesList == 0)
679             ShapeMap[Pkg->ID] = 2;
680          else
681             ShapeMap[Pkg->ID] = 3;
682       }
683    }
684    
685    // Load the list of packages from the command line into the show list
686    for (const char **I = CmdL.FileList + 1; *I != 0; I++)
687    {
688       // Process per-package flags
689       string P = *I;
690       bool Force = false;
691       if (P.length() > 3)
692       {
693          if (P.end()[-1] == '^')
694          {
695             Force = true;
696             P.erase(P.end()-1);
697          }
698          
699          if (P.end()[-1] == ',')
700             P.erase(P.end()-1);
701       }
702       
703       // Locate the package
704       pkgCache::PkgIterator Pkg = Cache.FindPkg(P);
705       if (Pkg.end() == true)
706       {
707          _error->Warning(_("Unable to locate package %s"),*I);
708          continue;
709       }
710       Show[Pkg->ID] = ToShow;
711       
712       if (Force == true)
713          Flags[Pkg->ID] |= ForceNR;
714    }
715    
716    // Little header
717    printf("digraph packages {\n");
718    printf("concentrate=true;\n");
719    printf("size=\"30,40\";\n");
720    
721    bool Act = true;
722    while (Act == true)
723    {
724       Act = false;
725       for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++)
726       {
727          // See we need to show this package
728          if (Show[Pkg->ID] == None || Show[Pkg->ID] >= DoneNR)
729             continue;
730          
731          // Colour as done
732          if (Show[Pkg->ID] == ToShowNR || (Flags[Pkg->ID] & ForceNR) == ForceNR)
733          {
734             // Pure Provides and missing packages have no deps!
735             if (ShapeMap[Pkg->ID] == 0 || ShapeMap[Pkg->ID] == 1)
736                Show[Pkg->ID] = Done;
737             else
738                Show[Pkg->ID] = DoneNR;
739          }       
740          else
741             Show[Pkg->ID] = Done;
742          Act = true;
743
744          // No deps to map out
745          if (Pkg->VersionList == 0 || Show[Pkg->ID] == DoneNR)
746             continue;
747          
748          pkgCache::VerIterator Ver = Pkg.VersionList();
749          for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; D++)
750          {
751             // See if anything can meet this dep
752             // Walk along the actual package providing versions
753             bool Hit = false;
754             pkgCache::PkgIterator DPkg = D.TargetPkg();
755             for (pkgCache::VerIterator I = DPkg.VersionList();
756                       I.end() == false && Hit == false; I++)
757             {
758                if (Cache.VS->CheckDep(I.VerStr(),D->CompareOp,D.TargetVer()) == true)
759                   Hit = true;
760             }
761             
762             // Follow all provides
763             for (pkgCache::PrvIterator I = DPkg.ProvidesList(); 
764                       I.end() == false && Hit == false; I++)
765             {
766                if (Cache.VS->CheckDep(I.ProvideVersion(),D->CompareOp,D.TargetVer()) == false)
767                   Hit = true;
768             }
769             
770             // Only graph critical deps     
771             if (D.IsCritical() == true)
772             {
773                printf("\"%s\" -> \"%s\"",Pkg.Name(),D.TargetPkg().Name());
774                
775                // Colour the node for recursion
776                if (Show[D.TargetPkg()->ID] <= DoneNR)
777                {
778                   /* If a conflicts does not meet anything in the database
779                      then show the relation but do not recurse */
780                   if (Hit == false && 
781                       (D->Type == pkgCache::Dep::Conflicts ||
782                        D->Type == pkgCache::Dep::Obsoletes))
783                   {
784                      if (Show[D.TargetPkg()->ID] == None && 
785                          Show[D.TargetPkg()->ID] != ToShow)
786                         Show[D.TargetPkg()->ID] = ToShowNR;
787                   }               
788                   else
789                   {
790                      if (GivenOnly == true && Show[D.TargetPkg()->ID] != ToShow)
791                         Show[D.TargetPkg()->ID] = ToShowNR;
792                      else
793                         Show[D.TargetPkg()->ID] = ToShow;
794                   }
795                }
796                
797                // Edge colour
798                switch(D->Type)
799                {
800                   case pkgCache::Dep::Conflicts:
801                   case pkgCache::Dep::Obsoletes:
802                   printf("[color=springgreen];\n");
803                   break;
804                   
805                   case pkgCache::Dep::PreDepends:
806                   printf("[color=blue];\n");
807                   break;
808                   
809                   default:
810                   printf(";\n");
811                   break;
812                }               
813             }       
814          }
815       }
816    }   
817    
818    /* Draw the box colours after the fact since we can not tell what colour
819       they should be until everything is finished drawing */
820    for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++)
821    {
822       if (Show[Pkg->ID] < DoneNR)
823          continue;
824       
825       // Orange box for early recursion stoppage
826       if (Show[Pkg->ID] == DoneNR)
827          printf("\"%s\" [color=orange,shape=%s];\n",Pkg.Name(),
828                 Shapes[ShapeMap[Pkg->ID]]);
829       else
830          printf("\"%s\" [shape=%s];\n",Pkg.Name(),
831                 Shapes[ShapeMap[Pkg->ID]]);
832    }
833    
834    printf("}\n");
835    return true;
836 }
837                                                                         /*}}}*/
838 // DoAdd - Perform an adding operation                                  /*{{{*/
839 // ---------------------------------------------------------------------
840 /* */
841 bool DoAdd(CommandLine &CmdL)
842 {
843    return _error->Error("Unimplemented");
844 #if 0   
845    // Make sure there is at least one argument
846    if (CmdL.FileSize() <= 1)
847       return _error->Error("You must give at least one file name");
848    
849    // Open the cache
850    FileFd CacheF(_config->FindFile("Dir::Cache::pkgcache"),FileFd::WriteAny);
851    if (_error->PendingError() == true)
852       return false;
853    
854    DynamicMMap Map(CacheF,MMap::Public);
855    if (_error->PendingError() == true)
856       return false;
857
858    OpTextProgress Progress(*_config);
859    pkgCacheGenerator Gen(Map,Progress);
860    if (_error->PendingError() == true)
861       return false;
862
863    unsigned long Length = CmdL.FileSize() - 1;
864    for (const char **I = CmdL.FileList + 1; *I != 0; I++)
865    {
866       Progress.OverallProgress(I - CmdL.FileList,Length,1,"Generating cache");
867       Progress.SubProgress(Length);
868
869       // Do the merge
870       FileFd TagF(*I,FileFd::ReadOnly);
871       debListParser Parser(TagF);
872       if (_error->PendingError() == true)
873          return _error->Error("Problem opening %s",*I);
874       
875       if (Gen.SelectFile(*I,"") == false)
876          return _error->Error("Problem with SelectFile");
877          
878       if (Gen.MergeList(Parser) == false)
879          return _error->Error("Problem with MergeList");
880    }
881
882    Progress.Done();
883    GCache = &Gen.GetCache();
884    Stats(CmdL);
885    
886    return true;
887 #endif   
888 }
889                                                                         /*}}}*/
890 // DisplayRecord - Displays the complete record for the package         /*{{{*/
891 // ---------------------------------------------------------------------
892 /* This displays the package record from the proper package index file. 
893    It is not used by DumpAvail for performance reasons. */
894 bool DisplayRecord(pkgCache::VerIterator V)
895 {
896    return cmdDisplayRecord(V, *GCache);
897 }
898                                                                         /*}}}*/
899 // Search - Perform a search                                            /*{{{*/
900 // ---------------------------------------------------------------------
901 /* This searches the package names and pacakge descriptions for a pattern */
902 bool Search(CommandLine &CmdL)
903 {
904    return cmdSearch(CmdL, *GCache);
905 }
906                                                                         /*}}}*/
907 bool SearchFile(CommandLine &CmdL)
908 {
909    return cmdSearchFile(CmdL, *GCache);
910 }
911
912 // ShowPackage - Dump the package record to the screen                  /*{{{*/
913 // ---------------------------------------------------------------------
914 /* */
915 bool ShowPackage(CommandLine &CmdL)
916 {   
917    return cmdShowPackage(CmdL, *GCache);
918 }
919                                                                         /*}}}*/
920 // ShowPkgNames - Show package names                                    /*{{{*/
921 // ---------------------------------------------------------------------
922 /* This does a prefix match on the first argument */
923 bool ShowPkgNames(CommandLine &CmdL)
924 {
925    pkgCache &Cache = *GCache;
926    pkgCache::PkgIterator I = Cache.PkgBegin();
927    bool All = _config->FindB("APT::Cache::AllNames", false);
928    
929    if (CmdL.FileList[1] != 0)
930    {
931       for (;I.end() != true; I++)
932       {
933          if (All == false && I->VersionList == 0)
934             continue;
935          
936          if (strncmp(I.Name(),CmdL.FileList[1],strlen(CmdL.FileList[1])) == 0)
937             cout << I.Name() << endl;
938       }
939
940       return true;
941    }
942    
943    // Show all pkgs
944    for (;I.end() != true; I++)
945    {
946       if (All == false && I->VersionList == 0)
947          continue;
948       cout << I.Name() << endl;
949    }
950    
951    return true;
952 }
953                                                                         /*}}}*/
954 // ShowSrcPackage - Show source package records                         /*{{{*/
955 // ---------------------------------------------------------------------
956 /* */
957 bool ShowSrcPackage(CommandLine &CmdL)
958 {
959    pkgSourceList List;
960    List.ReadMainList();
961    
962    // Create the text record parsers
963    pkgSrcRecords SrcRecs(List);
964    if (_error->PendingError() == true)
965       return false;
966
967    for (const char **I = CmdL.FileList + 1; *I != 0; I++)
968    {
969       SrcRecs.Restart();
970       
971       pkgSrcRecords::Parser *Parse;
972       while ((Parse = SrcRecs.Find(*I,false)) != 0)
973          cout << Parse->AsStr() << endl;;
974    }      
975    return true;
976 }
977                                                                         /*}}}*/
978 // Policy - Show the results of the preferences file                    /*{{{*/
979 // ---------------------------------------------------------------------
980 /* */
981 bool Policy(CommandLine &CmdL)
982 {
983    if (SrcList == 0)
984       return _error->Error("Generate must be enabled for this function");
985    
986    pkgCache &Cache = *GCache;
987    pkgPolicy Plcy(&Cache);
988    if (ReadPinFile(Plcy) == false)
989       return false;
990    
991    // Print out all of the package files
992    if (CmdL.FileList[1] == 0)
993    {
994       cout << _("Package Files:") << endl;   
995       for (pkgCache::PkgFileIterator F = Cache.FileBegin(); F.end() == false; F++)
996       {
997          // Locate the associated index files so we can derive a description
998          pkgIndexFile *Indx;
999          if (SrcList->FindIndex(F,Indx) == false &&
1000              _system->FindIndex(F,Indx) == false)
1001             return _error->Error(_("Cache is out of sync, can't x-ref a package file"));
1002          printf(_("%4i %s\n"),
1003                 Plcy.GetPriority(F),Indx->Describe(true).c_str());
1004          
1005          // Print the reference information for the package
1006          string Str = F.RelStr();
1007          if (Str.empty() == false)
1008             printf("     release %s\n",F.RelStr().c_str());
1009          if (F.Site() != 0 && F.Site()[0] != 0)
1010             printf("     origin %s\n",F.Site());
1011       }
1012       
1013       // Show any packages have explicit pins
1014       cout << _("Pinned Packages:") << endl;
1015       pkgCache::PkgIterator I = Cache.PkgBegin();
1016       for (;I.end() != true; I++)
1017       {
1018          if (Plcy.GetPriority(I) == 0)
1019             continue;
1020
1021          // Print the package name and the version we are forcing to
1022          cout << "     " << I.Name() << " -> ";
1023          
1024          pkgCache::VerIterator V = Plcy.GetMatch(I);
1025          if (V.end() == true)
1026             cout << _("(not found)") << endl;
1027          else
1028             cout << V.VerStr() << endl;
1029       }     
1030       
1031       return true;
1032    }
1033    
1034    // Print out detailed information for each package
1035    for (const char **I = CmdL.FileList + 1; *I != 0; I++)
1036    {
1037       pkgCache::PkgIterator Pkg = Cache.FindPkg(*I);
1038       if (Pkg.end() == true)
1039       {
1040          _error->Warning(_("Unable to locate package %s"),*I);
1041          continue;
1042       }
1043       
1044       cout << Pkg.Name() << ":" << endl;
1045       
1046       // Installed version
1047       cout << _("  Installed: ");
1048       if (Pkg->CurrentVer == 0)
1049          cout << _("(none)") << endl;
1050       else
1051          cout << Pkg.CurrentVer().VerStr() << endl;
1052       
1053       // Candidate Version 
1054       cout << _("  Candidate: ");
1055       pkgCache::VerIterator V = Plcy.GetCandidateVer(Pkg);
1056       if (V.end() == true)
1057          cout << _("(none)") << endl;
1058       else
1059          cout << V.VerStr() << endl;
1060
1061       // Pinned version
1062       if (Plcy.GetPriority(Pkg) != 0)
1063       {
1064          cout << _("  Package Pin: ");
1065          V = Plcy.GetMatch(Pkg);
1066          if (V.end() == true)
1067             cout << _("(not found)") << endl;
1068          else
1069             cout << V.VerStr() << endl;
1070       }
1071       
1072       // Show the priority tables
1073       cout << _("  Version Table:") << endl;
1074       for (V = Pkg.VersionList(); V.end() == false; V++)
1075       {
1076          if (Pkg.CurrentVer() == V)
1077             cout << " *** " << V.VerStr();
1078          else
1079             cout << "     " << V.VerStr();
1080          // CNC:2004-05-29
1081          if (Plcy.GetCandidateVer(Pkg) == V)
1082             cout << " " << Plcy.GetPriority(Pkg) << endl;
1083          else
1084             cout << " 0" << endl;
1085          for (pkgCache::VerFileIterator VF = V.FileList(); VF.end() == false; VF++)
1086          {
1087             // Locate the associated index files so we can derive a description
1088             pkgIndexFile *Indx;
1089             if (SrcList->FindIndex(VF.File(),Indx) == false &&
1090                 _system->FindIndex(VF.File(),Indx) == false)
1091                return _error->Error(_("Cache is out of sync, can't x-ref a package file"));
1092             printf(_("       %4i %s\n"),Plcy.GetPriority(VF.File()),
1093                    Indx->Describe(true).c_str());
1094          }       
1095       }      
1096    }
1097    
1098    return true;
1099 }
1100                                                                         /*}}}*/
1101 // GenCaches - Call the main cache generator                            /*{{{*/
1102 // ---------------------------------------------------------------------
1103 /* */
1104 bool GenCaches(CommandLine &Cmd)
1105 {
1106    OpTextProgress Progress(*_config);
1107    
1108    pkgSourceList List;
1109    if (List.ReadMainList() == false)
1110       return false;   
1111    return pkgMakeStatusCache(List,Progress);
1112 }
1113                                                                         /*}}}*/
1114 // ShowHelp - Show a help screen                                        /*{{{*/
1115 // ---------------------------------------------------------------------
1116 /* */
1117 bool ShowHelp(CommandLine &Cmd)
1118 {
1119    ioprintf(cout,_("%s %s for %s %s compiled on %s %s\n"),PACKAGE,VERSION,
1120             COMMON_OS,COMMON_CPU,__DATE__,__TIME__);
1121    
1122    if (_config->FindB("version") == true)
1123      return true;
1124
1125    cout << 
1126     _("Usage: apt-cache [options] command\n"
1127       "       apt-cache [options] add file1 [file2 ...]\n"
1128       "       apt-cache [options] showpkg pkg1 [pkg2 ...]\n"
1129       "       apt-cache [options] showsrc pkg1 [pkg2 ...]\n"
1130       "\n"
1131       "apt-cache is a low-level tool used to manipulate APT's binary\n"
1132       "cache files, and query information from them\n"
1133       "\n"
1134       "Commands:\n"
1135       "   add - Add a package file to the source cache\n"
1136       "   gencaches - Build both the package and source cache\n"
1137       "   showpkg - Show some general information for a single package\n"
1138       "   showsrc - Show source records\n"
1139       "   stats - Show some basic statistics\n"
1140       "   dump - Show the entire file in a terse form\n"
1141       "   dumpavail - Print an available file to stdout\n"
1142       "   unmet - Show unmet dependencies\n"
1143       "   search - Search the package list for a regex pattern\n"
1144       "   searchfile - Search the packages for a file\n"
1145       "   show - Show a readable record for the package\n"
1146       "   depends - Show raw dependency information for a package\n"
1147       "   whatdepends - Show packages depending on given capabilities\n"
1148       // "   rdepends - Show reverse dependency information for a package\n"
1149       "   whatprovides - Show packages that provide given capabilities\n"
1150       "   pkgnames - List the names of all packages\n"
1151       "   dotty - Generate package graphs for GraphVis\n"
1152       "   xvcg - Generate package graphs for xvcg\n"
1153       "   policy - Show policy settings\n"
1154 // CNC:2003-03-16
1155       );
1156 #ifdef WITH_LUA
1157       _lua->RunScripts("Scripts::AptCache::Help::Command");
1158 #endif
1159       cout << _(
1160       "\n"
1161       "Options:\n"
1162       "  -h   This help text.\n"
1163       "  -p=? The package cache.\n"
1164       "  -s=? The source cache.\n"
1165       "  -q   Disable progress indicator.\n"
1166       "  -i   Show only important deps for the unmet command.\n"
1167       "  -c=? Read this configuration file\n"
1168       "  -o=? Set an arbitary configuration option, eg -o dir::cache=/tmp\n"
1169       "See the apt-cache(8) and apt.conf(5) manual pages for more information.\n");
1170    return true;
1171 }
1172                                                                         /*}}}*/
1173 // CacheInitialize - Initialize things for apt-cache                    /*{{{*/
1174 // ---------------------------------------------------------------------
1175 /* */
1176 void CacheInitialize()
1177 {
1178    _config->Set("quiet",0);
1179    _config->Set("help",false);
1180 }
1181                                                                         /*}}}*/
1182
1183 int main(int argc,const char *argv[])
1184 {
1185    CommandLine::Args Args[] = {
1186       {'h',"help","help",0},
1187       {'v',"version","version",0},
1188       {'p',"pkg-cache","Dir::Cache::pkgcache",CommandLine::HasArg},
1189       {'s',"src-cache","Dir::Cache::srcpkgcache",CommandLine::HasArg},
1190       {'q',"quiet","quiet",CommandLine::IntLevel},
1191       {'i',"important","APT::Cache::Important",0},
1192       {'f',"full","APT::Cache::ShowFull",0},
1193       {'g',"generate","APT::Cache::Generate",0},
1194       {'a',"all-versions","APT::Cache::AllVersions",0},
1195       {0,"names-only","APT::Cache::NamesOnly",0},
1196       {'n',"all-names","APT::Cache::AllNames",0},
1197       {0,"recurse","APT::Cache::RecurseDepends",0},
1198       {'c',"config-file",0,CommandLine::ConfigFile},
1199       {'o',"option",0,CommandLine::ArbItem},
1200       {'n',"installed","APT::Cache::Installed",0},
1201       {0,0,0,0}};
1202    CommandLine::Dispatch CmdsA[] = {{"help",&ShowHelp},
1203                                     {"add",&DoAdd},
1204                                     {"gencaches",&GenCaches},
1205                                     {"showsrc",&ShowSrcPackage},
1206                                     {0,0}};
1207    CommandLine::Dispatch CmdsB[] = {{"showpkg",&DumpPackage},
1208                                     {"stats",&Stats},
1209                                     {"dump",&Dump},
1210                                     {"dumpavail",&DumpAvail},
1211                                     {"unmet",&UnMet},
1212                                     {"search",&Search},
1213                                     {"searchfile",&SearchFile},
1214                                     {"depends",&Depends},
1215                                     {"whatdepends",&WhatDepends},
1216                                     {"rdepends",&RDepends},
1217                                     {"whatprovides",&WhatProvides},
1218                                     {"dotty",&Dotty},
1219                                     {"xvcg",&XVcg},
1220                                     {"show",&ShowPackage},
1221                                     {"pkgnames",&ShowPkgNames},
1222                                     {"policy",&Policy},
1223 // CNC:2003-11-23
1224 #ifdef WITH_LUA
1225                                     {"script",&Script},
1226 #endif
1227                                     {0,0}};
1228
1229    CacheInitialize();
1230
1231    // Set up gettext support
1232    setlocale(LC_ALL,"");
1233    textdomain(PACKAGE);
1234
1235    // Parse the command line and initialize the package library
1236    CommandLine CmdL(Args,_config);
1237    if (pkgInitConfig(*_config) == false ||
1238        CmdL.Parse(argc,argv) == false ||
1239        pkgInitSystem(*_config,_system) == false)
1240    {
1241       _error->DumpErrors();
1242       return 100;
1243    }
1244
1245    // See if the help should be shown
1246    if (_config->FindB("help") == true ||
1247        CmdL.FileSize() == 0)
1248    {
1249       ShowHelp(CmdL);
1250       return 0;
1251    }
1252    
1253    // Deal with stdout not being a tty
1254    if (ttyname(STDOUT_FILENO) == 0 && _config->FindI("quiet",0) < 1)
1255       _config->Set("quiet","1");
1256
1257    // CNC:2004-02-18
1258    if (_system->LockRead() == false)
1259    {
1260       bool Errors = _error->PendingError();
1261       _error->DumpErrors();
1262       return Errors == true?100:0;
1263    }
1264
1265    if (CmdL.DispatchArg(CmdsA,false) == false && _error->PendingError() == false)
1266    { 
1267       MMap *Map = 0;
1268       if (_config->FindB("APT::Cache::Generate",true) == false)
1269       {
1270          Map = new MMap(*new FileFd(_config->FindFile("Dir::Cache::pkgcache"),
1271                                     FileFd::ReadOnly),MMap::Public|MMap::ReadOnly);
1272       }
1273       else
1274       {
1275          // Open the cache file
1276          SrcList = new pkgSourceList;
1277          SrcList->ReadMainList();
1278
1279          // Generate it and map it
1280          OpProgress Prog;
1281          pkgMakeStatusCache(*SrcList,Prog,&Map,true);
1282       }
1283       
1284       if (_error->PendingError() == false)
1285       {
1286          pkgCache Cache(Map);   
1287          GCache = &Cache;
1288 // CNC:2003-11-23
1289 #ifdef WITH_LUA
1290          _lua->SetCache(&Cache);
1291          double Consume = 0;
1292          if (argc > 1 && _error->PendingError() == false &&
1293              _lua->HasScripts("Scripts::AptCache::Command") == true)
1294          {
1295             _lua->SetGlobal("command_args", CmdL.FileList);
1296             _lua->SetGlobal("command_consume", 0.0);
1297             _lua->RunScripts("Scripts::AptCache::Command");
1298             Consume = _lua->GetGlobalNum("command_consume");
1299             _lua->ResetGlobals();
1300             _lua->ResetCaches();
1301          }
1302
1303          if (Consume == 0)
1304 #endif
1305          if (_error->PendingError() == false)
1306             CmdL.DispatchArg(CmdsB);
1307       }
1308       delete Map;
1309    }
1310    
1311    // Print any errors or warnings found during parsing
1312    if (_error->empty() == false)
1313    {
1314       bool Errors = _error->PendingError();
1315       _error->DumpErrors();
1316       return Errors == true?100:0;
1317    }
1318           
1319    return 0;
1320 }
1321
1322 // vim:sts=3:sw=3