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