* Skip version check if a build-dependency is provided ...
[ntk/apt.git] / cmdline / apt-cache.cc
CommitLineData
1164783d
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
b9d2ece3 3// $Id: apt-cache.cc,v 1.64 2003/05/15 09:39:38 piefel 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 ||
b2e465d6 1198 write(STDOUT_FILENO,Buffer,V.FileList()->Size+1) != 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
AL
1346 pkgDepCache::Policy Plcy;
1347
7e2e2d5d
AL
1348 for (const char **I = CmdL.FileList + 1; *I != 0; I++)
1349 {
1350 pkgCache::PkgIterator Pkg = Cache.FindPkg(*I);
1351 if (Pkg.end() == true)
1352 {
b2e465d6 1353 _error->Warning(_("Unable to locate package %s"),*I);
7e2e2d5d
AL
1354 continue;
1355 }
b2e465d6
AL
1356
1357 // Find the proper version to use.
648e3cb4
AL
1358 if (_config->FindB("APT::Cache::AllVersions","true") == true)
1359 {
1360 pkgCache::VerIterator V;
1361 for (V = Pkg.VersionList(); V.end() == false; V++)
1362 {
1363 if (DisplayRecord(V) == false)
1364 return false;
1365 }
1366 }
1367 else
1368 {
b2e465d6 1369 pkgCache::VerIterator V = Plcy.GetCandidateVer(Pkg);
648e3cb4
AL
1370 if (V.end() == true || V.FileList().end() == true)
1371 continue;
1372 if (DisplayRecord(V) == false)
1373 return false;
1374 }
7e2e2d5d 1375 }
7c1133fe
AL
1376 return true;
1377}
1378 /*}}}*/
1379// ShowPkgNames - Show package names /*{{{*/
1380// ---------------------------------------------------------------------
1381/* This does a prefix match on the first argument */
1382bool ShowPkgNames(CommandLine &CmdL)
1383{
1384 pkgCache &Cache = *GCache;
1385 pkgCache::PkgIterator I = Cache.PkgBegin();
1386 bool All = _config->FindB("APT::Cache::AllNames","false");
1387
1388 if (CmdL.FileList[1] != 0)
1389 {
1390 for (;I.end() != true; I++)
1391 {
1392 if (All == false && I->VersionList == 0)
1393 continue;
1394
1395 if (strncmp(I.Name(),CmdL.FileList[1],strlen(CmdL.FileList[1])) == 0)
1396 cout << I.Name() << endl;
1397 }
1398
1399 return true;
1400 }
1401
1402 // Show all pkgs
1403 for (;I.end() != true; I++)
1404 {
1405 if (All == false && I->VersionList == 0)
1406 continue;
1407 cout << I.Name() << endl;
1408 }
1409
7e2e2d5d
AL
1410 return true;
1411}
1412 /*}}}*/
f8f410f5
AL
1413// ShowSrcPackage - Show source package records /*{{{*/
1414// ---------------------------------------------------------------------
1415/* */
1416bool ShowSrcPackage(CommandLine &CmdL)
1417{
1418 pkgSourceList List;
1419 List.ReadMainList();
1420
1421 // Create the text record parsers
1422 pkgSrcRecords SrcRecs(List);
1423 if (_error->PendingError() == true)
1424 return false;
1425
1426 for (const char **I = CmdL.FileList + 1; *I != 0; I++)
1427 {
aaee8293
AL
1428 SrcRecs.Restart();
1429
f8f410f5
AL
1430 pkgSrcRecords::Parser *Parse;
1431 while ((Parse = SrcRecs.Find(*I,false)) != 0)
b2e465d6 1432 cout << Parse->AsStr() << endl;;
f8f410f5 1433 }
af87ab54
AL
1434 return true;
1435}
1436 /*}}}*/
1437// Policy - Show the results of the preferences file /*{{{*/
1438// ---------------------------------------------------------------------
1439/* */
1440bool Policy(CommandLine &CmdL)
1441{
1442 if (SrcList == 0)
1443 return _error->Error("Generate must be enabled for this function");
1444
1445 pkgCache &Cache = *GCache;
1446 pkgPolicy Plcy(&Cache);
1447 if (ReadPinFile(Plcy) == false)
1448 return false;
1449
1450 // Print out all of the package files
1451 if (CmdL.FileList[1] == 0)
1452 {
1453 cout << _("Package Files:") << endl;
1454 for (pkgCache::PkgFileIterator F = Cache.FileBegin(); F.end() == false; F++)
1455 {
1456 // Locate the associated index files so we can derive a description
1457 pkgIndexFile *Indx;
1458 if (SrcList->FindIndex(F,Indx) == false &&
1459 _system->FindIndex(F,Indx) == false)
1460 return _error->Error(_("Cache is out of sync, can't x-ref a package file"));
1461 printf(_("%4i %s\n"),
1462 Plcy.GetPriority(F),Indx->Describe(true).c_str());
1463
1464 // Print the reference information for the package
1465 string Str = F.RelStr();
1466 if (Str.empty() == false)
1467 printf(" release %s\n",F.RelStr().c_str());
1468 if (F.Site() != 0 && F.Site()[0] != 0)
1469 printf(" origin %s\n",F.Site());
1470 }
1471
1472 // Show any packages have explicit pins
1473 cout << _("Pinned Packages:") << endl;
1474 pkgCache::PkgIterator I = Cache.PkgBegin();
1475 for (;I.end() != true; I++)
1476 {
1477 if (Plcy.GetPriority(I) == 0)
1478 continue;
1479
1480 // Print the package name and the version we are forcing to
1481 cout << " " << I.Name() << " -> ";
1482
1483 pkgCache::VerIterator V = Plcy.GetMatch(I);
1484 if (V.end() == true)
1485 cout << _("(not found)") << endl;
1486 else
1487 cout << V.VerStr() << endl;
1488 }
1489
1490 return true;
1491 }
1492
1493 // Print out detailed information for each package
1494 for (const char **I = CmdL.FileList + 1; *I != 0; I++)
1495 {
1496 pkgCache::PkgIterator Pkg = Cache.FindPkg(*I);
1497 if (Pkg.end() == true)
1498 {
1499 _error->Warning(_("Unable to locate package %s"),*I);
1500 continue;
1501 }
1502
1503 cout << Pkg.Name() << ":" << endl;
1504
1505 // Installed version
1506 cout << _(" Installed: ");
1507 if (Pkg->CurrentVer == 0)
1508 cout << _("(none)") << endl;
1509 else
1510 cout << Pkg.CurrentVer().VerStr() << endl;
1511
1512 // Candidate Version
1513 cout << _(" Candidate: ");
1514 pkgCache::VerIterator V = Plcy.GetCandidateVer(Pkg);
1515 if (V.end() == true)
1516 cout << _("(none)") << endl;
1517 else
1518 cout << V.VerStr() << endl;
1519
1520 // Pinned version
1521 if (Plcy.GetPriority(Pkg) != 0)
1522 {
1523 cout << _(" Package Pin: ");
1524 V = Plcy.GetMatch(Pkg);
1525 if (V.end() == true)
1526 cout << _("(not found)") << endl;
1527 else
1528 cout << V.VerStr() << endl;
1529 }
1530
1531 // Show the priority tables
1532 cout << _(" Version Table:") << endl;
1533 for (V = Pkg.VersionList(); V.end() == false; V++)
1534 {
1535 if (Pkg.CurrentVer() == V)
1536 cout << " *** " << V.VerStr();
1537 else
1538 cout << " " << V.VerStr();
1539 cout << " " << Plcy.GetPriority(Pkg) << endl;
1540 for (pkgCache::VerFileIterator VF = V.FileList(); VF.end() == false; VF++)
1541 {
1542 // Locate the associated index files so we can derive a description
1543 pkgIndexFile *Indx;
1544 if (SrcList->FindIndex(VF.File(),Indx) == false &&
1545 _system->FindIndex(VF.File(),Indx) == false)
1546 return _error->Error(_("Cache is out of sync, can't x-ref a package file"));
1547 printf(_(" %4i %s\n"),Plcy.GetPriority(VF.File()),
1548 Indx->Describe(true).c_str());
1549 }
1550 }
1551 }
1552
f8f410f5
AL
1553 return true;
1554}
1555 /*}}}*/
880e9be4
AL
1556// GenCaches - Call the main cache generator /*{{{*/
1557// ---------------------------------------------------------------------
1558/* */
b0b4efb9 1559bool GenCaches(CommandLine &Cmd)
880e9be4 1560{
0a8e3465
AL
1561 OpTextProgress Progress(*_config);
1562
880e9be4 1563 pkgSourceList List;
b2e465d6
AL
1564 if (List.ReadMainList() == false)
1565 return false;
0a8e3465 1566 return pkgMakeStatusCache(List,Progress);
880e9be4
AL
1567}
1568 /*}}}*/
e1b74f61
AL
1569// ShowHelp - Show a help screen /*{{{*/
1570// ---------------------------------------------------------------------
1571/* */
b0b4efb9 1572bool ShowHelp(CommandLine &Cmd)
e1b74f61 1573{
b2e465d6
AL
1574 ioprintf(cout,_("%s %s for %s %s compiled on %s %s\n"),PACKAGE,VERSION,
1575 COMMON_OS,COMMON_CPU,__DATE__,__TIME__);
e1b74f61 1576
b2e465d6
AL
1577 cout <<
1578 _("Usage: apt-cache [options] command\n"
b9d2ece3 1579 " apt-cache [options] add file1 [file2 ...]\n"
b2e465d6 1580 " apt-cache [options] showpkg pkg1 [pkg2 ...]\n"
2d425135 1581 " apt-cache [options] showsrc pkg1 [pkg2 ...]\n"
b2e465d6
AL
1582 "\n"
1583 "apt-cache is a low-level tool used to manipulate APT's binary\n"
1584 "cache files, and query information from them\n"
1585 "\n"
1586 "Commands:\n"
bac2e715 1587 " add - Add a package file to the source cache\n"
b2e465d6
AL
1588 " gencaches - Build both the package and source cache\n"
1589 " showpkg - Show some general information for a single package\n"
2d425135 1590 " showsrc - Show source records\n"
b2e465d6
AL
1591 " stats - Show some basic statistics\n"
1592 " dump - Show the entire file in a terse form\n"
1593 " dumpavail - Print an available file to stdout\n"
1594 " unmet - Show unmet dependencies\n"
b2e465d6
AL
1595 " search - Search the package list for a regex pattern\n"
1596 " show - Show a readable record for the package\n"
1597 " depends - Show raw dependency information for a package\n"
eba2b51d 1598 " rdepends - Show reverse dependency information for a package\n"
b2e465d6
AL
1599 " pkgnames - List the names of all packages\n"
1600 " dotty - Generate package graphs for GraphVis\n"
fff4b7f3 1601 " xvcg - Generate package graphs for xvcg\n"
eba05d54 1602 " policy - Show policy settings\n"
b2e465d6
AL
1603 "\n"
1604 "Options:\n"
1605 " -h This help text.\n"
1606 " -p=? The package cache.\n"
1607 " -s=? The source cache.\n"
1608 " -q Disable progress indicator.\n"
1609 " -i Show only important deps for the unmet command.\n"
1610 " -c=? Read this configuration file\n"
1611 " -o=? Set an arbitary configuration option, eg -o dir::cache=/tmp\n"
1612 "See the apt-cache(8) and apt.conf(5) manual pages for more information.\n");
1613 return true;
e1b74f61
AL
1614}
1615 /*}}}*/
0a8e3465
AL
1616// CacheInitialize - Initialize things for apt-cache /*{{{*/
1617// ---------------------------------------------------------------------
1618/* */
1619void CacheInitialize()
1620{
1621 _config->Set("quiet",0);
1622 _config->Set("help",false);
1623}
1624 /*}}}*/
1164783d 1625
08e8f724 1626int main(int argc,const char *argv[])
1164783d 1627{
08e8f724
AL
1628 CommandLine::Args Args[] = {
1629 {'h',"help","help",0},
04aa15a8 1630 {'v',"version","version",0},
e1b74f61
AL
1631 {'p',"pkg-cache","Dir::Cache::pkgcache",CommandLine::HasArg},
1632 {'s',"src-cache","Dir::Cache::srcpkgcache",CommandLine::HasArg},
1633 {'q',"quiet","quiet",CommandLine::IntLevel},
76fbce56 1634 {'i',"important","APT::Cache::Important",0},
7e2e2d5d 1635 {'f',"full","APT::Cache::ShowFull",0},
b2e465d6 1636 {'g',"generate","APT::Cache::Generate",0},
648e3cb4 1637 {'a',"all-versions","APT::Cache::AllVersions",0},
7e2e2d5d 1638 {0,"names-only","APT::Cache::NamesOnly",0},
03eb0ddc 1639 {'n',"all-names","APT::Cache::AllNames",0},
b2e465d6 1640 {0,"recurse","APT::Cache::RecurseDepends",0},
e1b74f61
AL
1641 {'c',"config-file",0,CommandLine::ConfigFile},
1642 {'o',"option",0,CommandLine::ArbItem},
eba2b51d 1643 {'n',"installed","APT::Cache::Installed",0},
08e8f724 1644 {0,0,0,0}};
b0b4efb9
AL
1645 CommandLine::Dispatch CmdsA[] = {{"help",&ShowHelp},
1646 {"add",&DoAdd},
1647 {"gencaches",&GenCaches},
f8f410f5 1648 {"showsrc",&ShowSrcPackage},
b0b4efb9
AL
1649 {0,0}};
1650 CommandLine::Dispatch CmdsB[] = {{"showpkg",&DumpPackage},
1651 {"stats",&Stats},
1652 {"dump",&Dump},
1653 {"dumpavail",&DumpAvail},
1654 {"unmet",&UnMet},
9dbb421f 1655 {"search",&Search},
349cd3b8 1656 {"depends",&Depends},
eba2b51d 1657 {"rdepends",&RDepends},
3e94da1b 1658 {"dotty",&Dotty},
fff4b7f3 1659 {"xvcg",&XVcg},
7e2e2d5d 1660 {"show",&ShowPackage},
7c1133fe 1661 {"pkgnames",&ShowPkgNames},
af87ab54 1662 {"policy",&Policy},
b0b4efb9 1663 {0,0}};
0a8e3465
AL
1664
1665 CacheInitialize();
67111687
AL
1666
1667 // Set up gettext support
1668 setlocale(LC_ALL,"");
1669 textdomain(PACKAGE);
1670
e1b74f61
AL
1671 // Parse the command line and initialize the package library
1672 CommandLine CmdL(Args,_config);
b2e465d6
AL
1673 if (pkgInitConfig(*_config) == false ||
1674 CmdL.Parse(argc,argv) == false ||
1675 pkgInitSystem(*_config,_system) == false)
08e8f724
AL
1676 {
1677 _error->DumpErrors();
1678 return 100;
1164783d 1679 }
8efa2a3b 1680
e1b74f61
AL
1681 // See if the help should be shown
1682 if (_config->FindB("help") == true ||
1683 CmdL.FileSize() == 0)
b2e465d6
AL
1684 {
1685 ShowHelp(CmdL);
1686 return 0;
1687 }
1688
a9a5908d
AL
1689 // Deal with stdout not being a tty
1690 if (ttyname(STDOUT_FILENO) == 0 && _config->FindI("quiet",0) < 1)
1691 _config->Set("quiet","1");
1692
b0b4efb9 1693 if (CmdL.DispatchArg(CmdsA,false) == false && _error->PendingError() == false)
4b1b89c5 1694 {
2a3f3893 1695 MMap *Map = 0;
b2e465d6 1696 if (_config->FindB("APT::Cache::Generate",true) == false)
4b1b89c5
AL
1697 {
1698 Map = new MMap(*new FileFd(_config->FindFile("Dir::Cache::pkgcache"),
1699 FileFd::ReadOnly),MMap::Public|MMap::ReadOnly);
1700 }
1701 else
1702 {
1703 // Open the cache file
af87ab54
AL
1704 SrcList = new pkgSourceList;
1705 SrcList->ReadMainList();
f8f410f5 1706
4b1b89c5
AL
1707 // Generate it and map it
1708 OpProgress Prog;
af87ab54 1709 pkgMakeStatusCache(*SrcList,Prog,&Map,true);
4b1b89c5
AL
1710 }
1711
b0b4efb9 1712 if (_error->PendingError() == false)
1164783d 1713 {
b2e465d6 1714 pkgCache Cache(Map);
b0b4efb9
AL
1715 GCache = &Cache;
1716 if (_error->PendingError() == false)
1717 CmdL.DispatchArg(CmdsB);
803fafcb
AL
1718 }
1719 delete Map;
1164783d
AL
1720 }
1721
1722 // Print any errors or warnings found during parsing
1723 if (_error->empty() == false)
1724 {
0a8e3465 1725 bool Errors = _error->PendingError();
1164783d 1726 _error->DumpErrors();
0a8e3465 1727 return Errors == true?100:0;
1164783d
AL
1728 }
1729
1730 return 0;
1731}