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