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