Insert some newlines in the cdrom change media message.
[ntk/apt.git] / cmdline / apt-cache.cc
CommitLineData
1164783d
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
fff4b7f3 3// $Id: apt-cache.cc,v 1.62 2003/04/27 01:32:48 doogie 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);
532 bool DidSomething;
533 do
534 {
535 DidSomething = false;
536 for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++)
349cd3b8 537 {
b2e465d6
AL
538 if (Colours[Pkg->ID] != 1)
539 continue;
540 Colours[Pkg->ID] = 2;
541 DidSomething = true;
349cd3b8 542
b2e465d6
AL
543 pkgCache::VerIterator Ver = Pkg.VersionList();
544 if (Ver.end() == true)
349cd3b8 545 {
b2e465d6
AL
546 cout << '<' << Pkg.Name() << '>' << endl;
547 continue;
349cd3b8 548 }
b2e465d6
AL
549
550 cout << Pkg.Name() << endl;
551
552 for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; D++)
553 {
554 if ((D->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or)
555 cout << " |";
556 else
557 cout << " ";
558
559 // Show the package
560 pkgCache::PkgIterator Trg = D.TargetPkg();
561 if (Trg->VersionList == 0)
562 cout << D.DepType() << ": <" << Trg.Name() << ">" << endl;
563 else
564 cout << D.DepType() << ": " << Trg.Name() << endl;
565
566 if (Recurse == true)
567 Colours[D.TargetPkg()->ID]++;
568
569 // Display all solutions
570 SPtrArray<pkgCache::Version *> List = D.AllTargets();
571 pkgPrioSortList(Cache,List);
572 for (pkgCache::Version **I = List; *I != 0; I++)
573 {
574 pkgCache::VerIterator V(Cache,*I);
575 if (V != Cache.VerP + V.ParentPkg()->VersionList ||
576 V->ParentPkg == D->Package)
577 continue;
578 cout << " " << V.ParentPkg().Name() << endl;
579
580 if (Recurse == true)
581 Colours[D.ParentPkg()->ID]++;
582 }
583 }
584 }
349cd3b8 585 }
b2e465d6 586 while (DidSomething == true);
349cd3b8 587
3e94da1b
AL
588 return true;
589}
590 /*}}}*/
fff4b7f3
AL
591
592
593// xvcg - Generate a graph for xvcg /*{{{*/
594// ---------------------------------------------------------------------
595// Code contributed from Junichi Uekawa <dancer@debian.org> on 20 June 2002.
596
597bool XVcg(CommandLine &CmdL)
598{
599 pkgCache &Cache = *GCache;
600 bool GivenOnly = _config->FindB("APT::Cache::GivenOnly",false);
601
602 /* Normal packages are boxes
603 Pure Provides are triangles
604 Mixed are diamonds
605 rhomb are missing packages*/
606 const char *Shapes[] = {"ellipse","triangle","box","rhomb"};
607
608 /* Initialize the list of packages to show.
609 1 = To Show
610 2 = To Show no recurse
611 3 = Emitted no recurse
612 4 = Emitted
613 0 = None */
614 enum States {None=0, ToShow, ToShowNR, DoneNR, Done};
615 enum TheFlags {ForceNR=(1<<0)};
616 unsigned char *Show = new unsigned char[Cache.Head().PackageCount];
617 unsigned char *Flags = new unsigned char[Cache.Head().PackageCount];
618 unsigned char *ShapeMap = new unsigned char[Cache.Head().PackageCount];
619
620 // Show everything if no arguments given
621 if (CmdL.FileList[1] == 0)
622 for (unsigned long I = 0; I != Cache.Head().PackageCount; I++)
623 Show[I] = ToShow;
624 else
625 for (unsigned long I = 0; I != Cache.Head().PackageCount; I++)
626 Show[I] = None;
627 memset(Flags,0,sizeof(*Flags)*Cache.Head().PackageCount);
628
629 // Map the shapes
630 for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++)
631 {
632 if (Pkg->VersionList == 0)
633 {
634 // Missing
635 if (Pkg->ProvidesList == 0)
636 ShapeMap[Pkg->ID] = 0;
637 else
638 ShapeMap[Pkg->ID] = 1;
639 }
640 else
641 {
642 // Normal
643 if (Pkg->ProvidesList == 0)
644 ShapeMap[Pkg->ID] = 2;
645 else
646 ShapeMap[Pkg->ID] = 3;
647 }
648 }
649
650 // Load the list of packages from the command line into the show list
651 for (const char **I = CmdL.FileList + 1; *I != 0; I++)
652 {
653 // Process per-package flags
654 string P = *I;
655 bool Force = false;
656 if (P.length() > 3)
657 {
658 if (P.end()[-1] == '^')
659 {
660 Force = true;
661 P.erase(P.end()-1);
662 }
663
664 if (P.end()[-1] == ',')
665 P.erase(P.end()-1);
666 }
667
668 // Locate the package
669 pkgCache::PkgIterator Pkg = Cache.FindPkg(P);
670 if (Pkg.end() == true)
671 {
672 _error->Warning(_("Unable to locate package %s"),*I);
673 continue;
674 }
675 Show[Pkg->ID] = ToShow;
676
677 if (Force == true)
678 Flags[Pkg->ID] |= ForceNR;
679 }
680
681 // Little header
682 cout << "graph: { title: \"packages\"" << endl <<
683 "xmax: 700 ymax: 700 x: 30 y: 30" << endl <<
684 "layout_downfactor: 8" << endl;
685
686 bool Act = true;
687 while (Act == true)
688 {
689 Act = false;
690 for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++)
691 {
692 // See we need to show this package
693 if (Show[Pkg->ID] == None || Show[Pkg->ID] >= DoneNR)
694 continue;
695
696 //printf ("node: { title: \"%s\" label: \"%s\" }\n", Pkg.Name(), Pkg.Name());
697
698 // Colour as done
699 if (Show[Pkg->ID] == ToShowNR || (Flags[Pkg->ID] & ForceNR) == ForceNR)
700 {
701 // Pure Provides and missing packages have no deps!
702 if (ShapeMap[Pkg->ID] == 0 || ShapeMap[Pkg->ID] == 1)
703 Show[Pkg->ID] = Done;
704 else
705 Show[Pkg->ID] = DoneNR;
706 }
707 else
708 Show[Pkg->ID] = Done;
709 Act = true;
710
711 // No deps to map out
712 if (Pkg->VersionList == 0 || Show[Pkg->ID] == DoneNR)
713 continue;
714
715 pkgCache::VerIterator Ver = Pkg.VersionList();
716 for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; D++)
717 {
718 // See if anything can meet this dep
719 // Walk along the actual package providing versions
720 bool Hit = false;
721 pkgCache::PkgIterator DPkg = D.TargetPkg();
722 for (pkgCache::VerIterator I = DPkg.VersionList();
723 I.end() == false && Hit == false; I++)
724 {
725 if (Cache.VS->CheckDep(I.VerStr(),D->CompareOp,D.TargetVer()) == true)
726 Hit = true;
727 }
728
729 // Follow all provides
730 for (pkgCache::PrvIterator I = DPkg.ProvidesList();
731 I.end() == false && Hit == false; I++)
732 {
733 if (Cache.VS->CheckDep(I.ProvideVersion(),D->CompareOp,D.TargetVer()) == false)
734 Hit = true;
735 }
736
737
738 // Only graph critical deps
739 if (D.IsCritical() == true)
740 {
741 printf ("edge: { sourcename: \"%s\" targetname: \"%s\" class: 2 ",Pkg.Name(), D.TargetPkg().Name() );
742
743 // Colour the node for recursion
744 if (Show[D.TargetPkg()->ID] <= DoneNR)
745 {
746 /* If a conflicts does not meet anything in the database
747 then show the relation but do not recurse */
748 if (Hit == false &&
749 (D->Type == pkgCache::Dep::Conflicts ||
750 D->Type == pkgCache::Dep::Obsoletes))
751 {
752 if (Show[D.TargetPkg()->ID] == None &&
753 Show[D.TargetPkg()->ID] != ToShow)
754 Show[D.TargetPkg()->ID] = ToShowNR;
755 }
756 else
757 {
758 if (GivenOnly == true && Show[D.TargetPkg()->ID] != ToShow)
759 Show[D.TargetPkg()->ID] = ToShowNR;
760 else
761 Show[D.TargetPkg()->ID] = ToShow;
762 }
763 }
764
765 // Edge colour
766 switch(D->Type)
767 {
768 case pkgCache::Dep::Conflicts:
769 printf("label: \"conflicts\" color: lightgreen }\n");
770 break;
771 case pkgCache::Dep::Obsoletes:
772 printf("label: \"obsoletes\" color: lightgreen }\n");
773 break;
774
775 case pkgCache::Dep::PreDepends:
776 printf("label: \"predepends\" color: blue }\n");
777 break;
778
779 default:
780 printf("}\n");
781 break;
782 }
783 }
784 }
785 }
786 }
787
788 /* Draw the box colours after the fact since we can not tell what colour
789 they should be until everything is finished drawing */
790 for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++)
791 {
792 if (Show[Pkg->ID] < DoneNR)
793 continue;
794
795 if (Show[Pkg->ID] == DoneNR)
796 printf("node: { title: \"%s\" label: \"%s\" color: orange shape: %s }\n", Pkg.Name(), Pkg.Name(),
797 Shapes[ShapeMap[Pkg->ID]]);
798 else
799 printf("node: { title: \"%s\" label: \"%s\" shape: %s }\n", Pkg.Name(), Pkg.Name(),
800 Shapes[ShapeMap[Pkg->ID]]);
801
802 }
803
804 printf("}\n");
805 return true;
806}
807 /*}}}*/
808
809
3e94da1b
AL
810// Dotty - Generate a graph for Dotty /*{{{*/
811// ---------------------------------------------------------------------
812/* Dotty is the graphvis program for generating graphs. It is a fairly
813 simple queuing algorithm that just writes dependencies and nodes.
814 http://www.research.att.com/sw/tools/graphviz/ */
815bool Dotty(CommandLine &CmdL)
816{
817 pkgCache &Cache = *GCache;
818 bool GivenOnly = _config->FindB("APT::Cache::GivenOnly",false);
819
820 /* Normal packages are boxes
821 Pure Provides are triangles
822 Mixed are diamonds
823 Hexagons are missing packages*/
824 const char *Shapes[] = {"hexagon","triangle","box","diamond"};
825
826 /* Initialize the list of packages to show.
827 1 = To Show
828 2 = To Show no recurse
829 3 = Emitted no recurse
830 4 = Emitted
831 0 = None */
832 enum States {None=0, ToShow, ToShowNR, DoneNR, Done};
833 enum TheFlags {ForceNR=(1<<0)};
834 unsigned char *Show = new unsigned char[Cache.Head().PackageCount];
835 unsigned char *Flags = new unsigned char[Cache.Head().PackageCount];
836 unsigned char *ShapeMap = new unsigned char[Cache.Head().PackageCount];
837
838 // Show everything if no arguments given
839 if (CmdL.FileList[1] == 0)
840 for (unsigned long I = 0; I != Cache.Head().PackageCount; I++)
841 Show[I] = ToShow;
842 else
843 for (unsigned long I = 0; I != Cache.Head().PackageCount; I++)
844 Show[I] = None;
845 memset(Flags,0,sizeof(*Flags)*Cache.Head().PackageCount);
846
847 // Map the shapes
848 for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++)
849 {
850 if (Pkg->VersionList == 0)
851 {
852 // Missing
853 if (Pkg->ProvidesList == 0)
854 ShapeMap[Pkg->ID] = 0;
855 else
856 ShapeMap[Pkg->ID] = 1;
857 }
858 else
859 {
860 // Normal
861 if (Pkg->ProvidesList == 0)
862 ShapeMap[Pkg->ID] = 2;
863 else
864 ShapeMap[Pkg->ID] = 3;
865 }
866 }
867
868 // Load the list of packages from the command line into the show list
869 for (const char **I = CmdL.FileList + 1; *I != 0; I++)
870 {
871 // Process per-package flags
872 string P = *I;
873 bool Force = false;
874 if (P.length() > 3)
875 {
876 if (P.end()[-1] == '^')
877 {
878 Force = true;
879 P.erase(P.end()-1);
880 }
881
882 if (P.end()[-1] == ',')
883 P.erase(P.end()-1);
884 }
885
886 // Locate the package
887 pkgCache::PkgIterator Pkg = Cache.FindPkg(P);
888 if (Pkg.end() == true)
889 {
b2e465d6 890 _error->Warning(_("Unable to locate package %s"),*I);
3e94da1b
AL
891 continue;
892 }
893 Show[Pkg->ID] = ToShow;
894
895 if (Force == true)
896 Flags[Pkg->ID] |= ForceNR;
897 }
898
899 // Little header
900 printf("digraph packages {\n");
901 printf("concentrate=true;\n");
902 printf("size=\"30,40\";\n");
903
904 bool Act = true;
905 while (Act == true)
906 {
907 Act = false;
908 for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++)
909 {
910 // See we need to show this package
911 if (Show[Pkg->ID] == None || Show[Pkg->ID] >= DoneNR)
912 continue;
913
914 // Colour as done
915 if (Show[Pkg->ID] == ToShowNR || (Flags[Pkg->ID] & ForceNR) == ForceNR)
916 {
917 // Pure Provides and missing packages have no deps!
918 if (ShapeMap[Pkg->ID] == 0 || ShapeMap[Pkg->ID] == 1)
919 Show[Pkg->ID] = Done;
920 else
921 Show[Pkg->ID] = DoneNR;
922 }
923 else
924 Show[Pkg->ID] = Done;
925 Act = true;
926
927 // No deps to map out
928 if (Pkg->VersionList == 0 || Show[Pkg->ID] == DoneNR)
929 continue;
930
931 pkgCache::VerIterator Ver = Pkg.VersionList();
932 for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; D++)
933 {
934 // See if anything can meet this dep
935 // Walk along the actual package providing versions
936 bool Hit = false;
937 pkgCache::PkgIterator DPkg = D.TargetPkg();
938 for (pkgCache::VerIterator I = DPkg.VersionList();
939 I.end() == false && Hit == false; I++)
940 {
b2e465d6 941 if (Cache.VS->CheckDep(I.VerStr(),D->CompareOp,D.TargetVer()) == true)
3e94da1b
AL
942 Hit = true;
943 }
944
945 // Follow all provides
946 for (pkgCache::PrvIterator I = DPkg.ProvidesList();
947 I.end() == false && Hit == false; I++)
948 {
b2e465d6 949 if (Cache.VS->CheckDep(I.ProvideVersion(),D->CompareOp,D.TargetVer()) == false)
3e94da1b
AL
950 Hit = true;
951 }
952
953 // Only graph critical deps
954 if (D.IsCritical() == true)
955 {
956 printf("\"%s\" -> \"%s\"",Pkg.Name(),D.TargetPkg().Name());
957
958 // Colour the node for recursion
959 if (Show[D.TargetPkg()->ID] <= DoneNR)
960 {
961 /* If a conflicts does not meet anything in the database
962 then show the relation but do not recurse */
b2e465d6
AL
963 if (Hit == false &&
964 (D->Type == pkgCache::Dep::Conflicts ||
965 D->Type == pkgCache::Dep::Obsoletes))
3e94da1b
AL
966 {
967 if (Show[D.TargetPkg()->ID] == None &&
968 Show[D.TargetPkg()->ID] != ToShow)
969 Show[D.TargetPkg()->ID] = ToShowNR;
970 }
971 else
972 {
973 if (GivenOnly == true && Show[D.TargetPkg()->ID] != ToShow)
974 Show[D.TargetPkg()->ID] = ToShowNR;
975 else
976 Show[D.TargetPkg()->ID] = ToShow;
977 }
978 }
979
980 // Edge colour
981 switch(D->Type)
982 {
983 case pkgCache::Dep::Conflicts:
b2e465d6 984 case pkgCache::Dep::Obsoletes:
3e94da1b
AL
985 printf("[color=springgreen];\n");
986 break;
987
988 case pkgCache::Dep::PreDepends:
989 printf("[color=blue];\n");
990 break;
991
992 default:
993 printf(";\n");
994 break;
995 }
996 }
997 }
998 }
999 }
1000
1001 /* Draw the box colours after the fact since we can not tell what colour
1002 they should be until everything is finished drawing */
1003 for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++)
1004 {
1005 if (Show[Pkg->ID] < DoneNR)
1006 continue;
1007
1008 // Orange box for early recursion stoppage
1009 if (Show[Pkg->ID] == DoneNR)
1010 printf("\"%s\" [color=orange,shape=%s];\n",Pkg.Name(),
1011 Shapes[ShapeMap[Pkg->ID]]);
1012 else
1013 printf("\"%s\" [shape=%s];\n",Pkg.Name(),
1014 Shapes[ShapeMap[Pkg->ID]]);
1015 }
1016
1017 printf("}\n");
ad00ae81
AL
1018 return true;
1019}
1020 /*}}}*/
1021// DoAdd - Perform an adding operation /*{{{*/
1022// ---------------------------------------------------------------------
1023/* */
e1b74f61 1024bool DoAdd(CommandLine &CmdL)
ad00ae81 1025{
b2e465d6
AL
1026 return _error->Error("Unimplemented");
1027#if 0
e1b74f61
AL
1028 // Make sure there is at least one argument
1029 if (CmdL.FileSize() <= 1)
1030 return _error->Error("You must give at least one file name");
ad00ae81
AL
1031
1032 // Open the cache
018f1533 1033 FileFd CacheF(_config->FindFile("Dir::Cache::pkgcache"),FileFd::WriteAny);
ad00ae81
AL
1034 if (_error->PendingError() == true)
1035 return false;
1036
1037 DynamicMMap Map(CacheF,MMap::Public);
1038 if (_error->PendingError() == true)
1039 return false;
404ec98e 1040
0a8e3465 1041 OpTextProgress Progress(*_config);
404ec98e 1042 pkgCacheGenerator Gen(Map,Progress);
ad00ae81
AL
1043 if (_error->PendingError() == true)
1044 return false;
1045
e1b74f61
AL
1046 unsigned long Length = CmdL.FileSize() - 1;
1047 for (const char **I = CmdL.FileList + 1; *I != 0; I++)
ad00ae81 1048 {
e1b74f61 1049 Progress.OverallProgress(I - CmdL.FileList,Length,1,"Generating cache");
018f1533
AL
1050 Progress.SubProgress(Length);
1051
ad00ae81 1052 // Do the merge
e1b74f61 1053 FileFd TagF(*I,FileFd::ReadOnly);
ad00ae81
AL
1054 debListParser Parser(TagF);
1055 if (_error->PendingError() == true)
e1b74f61 1056 return _error->Error("Problem opening %s",*I);
ad00ae81 1057
b2e465d6 1058 if (Gen.SelectFile(*I,"") == false)
ad00ae81
AL
1059 return _error->Error("Problem with SelectFile");
1060
1061 if (Gen.MergeList(Parser) == false)
1062 return _error->Error("Problem with MergeList");
1164783d 1063 }
404ec98e
AL
1064
1065 Progress.Done();
b0b4efb9
AL
1066 GCache = &Gen.GetCache();
1067 Stats(CmdL);
ad00ae81 1068
7e2e2d5d 1069 return true;
b2e465d6 1070#endif
7e2e2d5d
AL
1071}
1072 /*}}}*/
1073// DisplayRecord - Displays the complete record for the package /*{{{*/
1074// ---------------------------------------------------------------------
1075/* This displays the package record from the proper package index file.
1076 It is not used by DumpAvail for performance reasons. */
1077bool DisplayRecord(pkgCache::VerIterator V)
1078{
1079 // Find an appropriate file
1080 pkgCache::VerFileIterator Vf = V.FileList();
1081 for (; Vf.end() == false; Vf++)
1082 if ((Vf.File()->Flags & pkgCache::Flag::NotSource) == 0)
1083 break;
1084 if (Vf.end() == true)
1085 Vf = V.FileList();
1086
1087 // Check and load the package list file
1088 pkgCache::PkgFileIterator I = Vf.File();
1089 if (I.IsOk() == false)
b2e465d6 1090 return _error->Error(_("Package file %s is out of sync."),I.FileName());
7e2e2d5d
AL
1091
1092 FileFd PkgF(I.FileName(),FileFd::ReadOnly);
1093 if (_error->PendingError() == true)
1094 return false;
1095
1096 // Read the record and then write it out again.
b2e465d6
AL
1097 unsigned char *Buffer = new unsigned char[GCache->HeaderP->MaxVerFileSize+1];
1098 Buffer[V.FileList()->Size] = '\n';
7e2e2d5d
AL
1099 if (PkgF.Seek(V.FileList()->Offset) == false ||
1100 PkgF.Read(Buffer,V.FileList()->Size) == false ||
b2e465d6 1101 write(STDOUT_FILENO,Buffer,V.FileList()->Size+1) != V.FileList()->Size+1)
7e2e2d5d
AL
1102 {
1103 delete [] Buffer;
1104 return false;
1105 }
1106
1107 delete [] Buffer;
1108
9dbb421f
AL
1109 return true;
1110}
1111 /*}}}*/
1112// Search - Perform a search /*{{{*/
1113// ---------------------------------------------------------------------
1114/* This searches the package names and pacakge descriptions for a pattern */
b2e465d6
AL
1115struct ExVerFile
1116{
1117 pkgCache::VerFile *Vf;
1118 bool NameMatch;
1119};
1120
9dbb421f
AL
1121bool Search(CommandLine &CmdL)
1122{
1123 pkgCache &Cache = *GCache;
7e2e2d5d
AL
1124 bool ShowFull = _config->FindB("APT::Cache::ShowFull",false);
1125 bool NamesOnly = _config->FindB("APT::Cache::NamesOnly",false);
b2e465d6
AL
1126 unsigned NumPatterns = CmdL.FileSize() -1;
1127
1128 pkgDepCache::Policy Plcy;
9dbb421f
AL
1129
1130 // Make sure there is at least one argument
b2e465d6
AL
1131 if (NumPatterns < 1)
1132 return _error->Error(_("You must give exactly one pattern"));
9dbb421f
AL
1133
1134 // Compile the regex pattern
b2e465d6
AL
1135 regex_t *Patterns = new regex_t[NumPatterns];
1136 memset(Patterns,0,sizeof(*Patterns)*NumPatterns);
1137 for (unsigned I = 0; I != NumPatterns; I++)
1138 {
1139 if (regcomp(&Patterns[I],CmdL.FileList[I+1],REG_EXTENDED | REG_ICASE |
1140 REG_NOSUB) != 0)
1141 {
1142 for (; I != 0; I--)
1143 regfree(&Patterns[I]);
1144 return _error->Error("Regex compilation error");
1145 }
1146 }
9dbb421f
AL
1147
1148 // Create the text record parser
1149 pkgRecords Recs(Cache);
1150 if (_error->PendingError() == true)
b2e465d6
AL
1151 {
1152 for (unsigned I = 0; I != NumPatterns; I++)
1153 regfree(&Patterns[I]);
9dbb421f 1154 return false;
b2e465d6 1155 }
9dbb421f 1156
b2e465d6
AL
1157 ExVerFile *VFList = new ExVerFile[Cache.HeaderP->PackageCount+1];
1158 memset(VFList,0,sizeof(*VFList)*Cache.HeaderP->PackageCount+1);
1159
1160 // Map versions that we want to write out onto the VerList array.
1161 for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
9dbb421f 1162 {
0f2fa322 1163 VFList[P->ID].NameMatch = NumPatterns != 0;
b2e465d6
AL
1164 for (unsigned I = 0; I != NumPatterns; I++)
1165 {
1166 if (regexec(&Patterns[I],P.Name(),0,0,0) == 0)
0f2fa322
AL
1167 VFList[P->ID].NameMatch &= true;
1168 else
1169 VFList[P->ID].NameMatch = false;
b2e465d6 1170 }
c29652b0 1171
b2e465d6
AL
1172 // Doing names only, drop any that dont match..
1173 if (NamesOnly == true && VFList[P->ID].NameMatch == false)
1174 continue;
1175
1176 // Find the proper version to use.
1177 pkgCache::VerIterator V = Plcy.GetCandidateVer(P);
c29652b0
AL
1178 if (V.end() == false)
1179 VFList[P->ID].Vf = V.FileList();
1180 }
1181
1182 // Include all the packages that provide matching names too
1183 for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
1184 {
1185 if (VFList[P->ID].NameMatch == false)
7e2e2d5d 1186 continue;
c29652b0
AL
1187
1188 for (pkgCache::PrvIterator Prv = P.ProvidesList() ; Prv.end() == false; Prv++)
1189 {
1190 pkgCache::VerIterator V = Plcy.GetCandidateVer(Prv.OwnerPkg());
1191 if (V.end() == false)
1192 {
1193 VFList[Prv.OwnerPkg()->ID].Vf = V.FileList();
1194 VFList[Prv.OwnerPkg()->ID].NameMatch = true;
1195 }
1196 }
b2e465d6 1197 }
c29652b0 1198
b2e465d6 1199 LocalitySort(&VFList->Vf,Cache.HeaderP->PackageCount,sizeof(*VFList));
7e2e2d5d 1200
b2e465d6
AL
1201 // Iterate over all the version records and check them
1202 for (ExVerFile *J = VFList; J->Vf != 0; J++)
1203 {
1204 pkgRecords::Parser &P = Recs.Lookup(pkgCache::VerFileIterator(Cache,J->Vf));
0f2fa322
AL
1205
1206 bool Match = true;
1207 if (J->NameMatch == false)
1208 {
1209 string LongDesc = P.LongDesc();
1210 Match = NumPatterns != 0;
1211 for (unsigned I = 0; I != NumPatterns; I++)
1212 {
1213 if (regexec(&Patterns[I],LongDesc.c_str(),0,0,0) == 0)
1214 Match &= true;
1215 else
1216 Match = false;
1217 }
1218 }
b2e465d6
AL
1219
1220 if (Match == true)
9dbb421f 1221 {
7e2e2d5d 1222 if (ShowFull == true)
b2e465d6
AL
1223 {
1224 const char *Start;
1225 const char *End;
1226 P.GetRec(Start,End);
1227 fwrite(Start,End-Start,1,stdout);
1228 putc('\n',stdout);
1229 }
7e2e2d5d 1230 else
b2e465d6
AL
1231 printf("%s - %s\n",P.Name().c_str(),P.ShortDesc().c_str());
1232 }
9dbb421f
AL
1233 }
1234
b2e465d6
AL
1235 delete [] VFList;
1236 for (unsigned I = 0; I != NumPatterns; I++)
1237 regfree(&Patterns[I]);
1238 if (ferror(stdout))
1239 return _error->Error("Write to stdout failed");
1164783d
AL
1240 return true;
1241}
1242 /*}}}*/
7e2e2d5d
AL
1243// ShowPackage - Dump the package record to the screen /*{{{*/
1244// ---------------------------------------------------------------------
1245/* */
1246bool ShowPackage(CommandLine &CmdL)
1247{
1248 pkgCache &Cache = *GCache;
b2e465d6
AL
1249 pkgDepCache::Policy Plcy;
1250
7e2e2d5d
AL
1251 for (const char **I = CmdL.FileList + 1; *I != 0; I++)
1252 {
1253 pkgCache::PkgIterator Pkg = Cache.FindPkg(*I);
1254 if (Pkg.end() == true)
1255 {
b2e465d6 1256 _error->Warning(_("Unable to locate package %s"),*I);
7e2e2d5d
AL
1257 continue;
1258 }
b2e465d6
AL
1259
1260 // Find the proper version to use.
648e3cb4
AL
1261 if (_config->FindB("APT::Cache::AllVersions","true") == true)
1262 {
1263 pkgCache::VerIterator V;
1264 for (V = Pkg.VersionList(); V.end() == false; V++)
1265 {
1266 if (DisplayRecord(V) == false)
1267 return false;
1268 }
1269 }
1270 else
1271 {
b2e465d6 1272 pkgCache::VerIterator V = Plcy.GetCandidateVer(Pkg);
648e3cb4
AL
1273 if (V.end() == true || V.FileList().end() == true)
1274 continue;
1275 if (DisplayRecord(V) == false)
1276 return false;
1277 }
7e2e2d5d 1278 }
7c1133fe
AL
1279 return true;
1280}
1281 /*}}}*/
1282// ShowPkgNames - Show package names /*{{{*/
1283// ---------------------------------------------------------------------
1284/* This does a prefix match on the first argument */
1285bool ShowPkgNames(CommandLine &CmdL)
1286{
1287 pkgCache &Cache = *GCache;
1288 pkgCache::PkgIterator I = Cache.PkgBegin();
1289 bool All = _config->FindB("APT::Cache::AllNames","false");
1290
1291 if (CmdL.FileList[1] != 0)
1292 {
1293 for (;I.end() != true; I++)
1294 {
1295 if (All == false && I->VersionList == 0)
1296 continue;
1297
1298 if (strncmp(I.Name(),CmdL.FileList[1],strlen(CmdL.FileList[1])) == 0)
1299 cout << I.Name() << endl;
1300 }
1301
1302 return true;
1303 }
1304
1305 // Show all pkgs
1306 for (;I.end() != true; I++)
1307 {
1308 if (All == false && I->VersionList == 0)
1309 continue;
1310 cout << I.Name() << endl;
1311 }
1312
7e2e2d5d
AL
1313 return true;
1314}
1315 /*}}}*/
f8f410f5
AL
1316// ShowSrcPackage - Show source package records /*{{{*/
1317// ---------------------------------------------------------------------
1318/* */
1319bool ShowSrcPackage(CommandLine &CmdL)
1320{
1321 pkgSourceList List;
1322 List.ReadMainList();
1323
1324 // Create the text record parsers
1325 pkgSrcRecords SrcRecs(List);
1326 if (_error->PendingError() == true)
1327 return false;
1328
1329 for (const char **I = CmdL.FileList + 1; *I != 0; I++)
1330 {
aaee8293
AL
1331 SrcRecs.Restart();
1332
f8f410f5
AL
1333 pkgSrcRecords::Parser *Parse;
1334 while ((Parse = SrcRecs.Find(*I,false)) != 0)
b2e465d6 1335 cout << Parse->AsStr() << endl;;
f8f410f5 1336 }
af87ab54
AL
1337 return true;
1338}
1339 /*}}}*/
1340// Policy - Show the results of the preferences file /*{{{*/
1341// ---------------------------------------------------------------------
1342/* */
1343bool Policy(CommandLine &CmdL)
1344{
1345 if (SrcList == 0)
1346 return _error->Error("Generate must be enabled for this function");
1347
1348 pkgCache &Cache = *GCache;
1349 pkgPolicy Plcy(&Cache);
1350 if (ReadPinFile(Plcy) == false)
1351 return false;
1352
1353 // Print out all of the package files
1354 if (CmdL.FileList[1] == 0)
1355 {
1356 cout << _("Package Files:") << endl;
1357 for (pkgCache::PkgFileIterator F = Cache.FileBegin(); F.end() == false; F++)
1358 {
1359 // Locate the associated index files so we can derive a description
1360 pkgIndexFile *Indx;
1361 if (SrcList->FindIndex(F,Indx) == false &&
1362 _system->FindIndex(F,Indx) == false)
1363 return _error->Error(_("Cache is out of sync, can't x-ref a package file"));
1364 printf(_("%4i %s\n"),
1365 Plcy.GetPriority(F),Indx->Describe(true).c_str());
1366
1367 // Print the reference information for the package
1368 string Str = F.RelStr();
1369 if (Str.empty() == false)
1370 printf(" release %s\n",F.RelStr().c_str());
1371 if (F.Site() != 0 && F.Site()[0] != 0)
1372 printf(" origin %s\n",F.Site());
1373 }
1374
1375 // Show any packages have explicit pins
1376 cout << _("Pinned Packages:") << endl;
1377 pkgCache::PkgIterator I = Cache.PkgBegin();
1378 for (;I.end() != true; I++)
1379 {
1380 if (Plcy.GetPriority(I) == 0)
1381 continue;
1382
1383 // Print the package name and the version we are forcing to
1384 cout << " " << I.Name() << " -> ";
1385
1386 pkgCache::VerIterator V = Plcy.GetMatch(I);
1387 if (V.end() == true)
1388 cout << _("(not found)") << endl;
1389 else
1390 cout << V.VerStr() << endl;
1391 }
1392
1393 return true;
1394 }
1395
1396 // Print out detailed information for each package
1397 for (const char **I = CmdL.FileList + 1; *I != 0; I++)
1398 {
1399 pkgCache::PkgIterator Pkg = Cache.FindPkg(*I);
1400 if (Pkg.end() == true)
1401 {
1402 _error->Warning(_("Unable to locate package %s"),*I);
1403 continue;
1404 }
1405
1406 cout << Pkg.Name() << ":" << endl;
1407
1408 // Installed version
1409 cout << _(" Installed: ");
1410 if (Pkg->CurrentVer == 0)
1411 cout << _("(none)") << endl;
1412 else
1413 cout << Pkg.CurrentVer().VerStr() << endl;
1414
1415 // Candidate Version
1416 cout << _(" Candidate: ");
1417 pkgCache::VerIterator V = Plcy.GetCandidateVer(Pkg);
1418 if (V.end() == true)
1419 cout << _("(none)") << endl;
1420 else
1421 cout << V.VerStr() << endl;
1422
1423 // Pinned version
1424 if (Plcy.GetPriority(Pkg) != 0)
1425 {
1426 cout << _(" Package Pin: ");
1427 V = Plcy.GetMatch(Pkg);
1428 if (V.end() == true)
1429 cout << _("(not found)") << endl;
1430 else
1431 cout << V.VerStr() << endl;
1432 }
1433
1434 // Show the priority tables
1435 cout << _(" Version Table:") << endl;
1436 for (V = Pkg.VersionList(); V.end() == false; V++)
1437 {
1438 if (Pkg.CurrentVer() == V)
1439 cout << " *** " << V.VerStr();
1440 else
1441 cout << " " << V.VerStr();
1442 cout << " " << Plcy.GetPriority(Pkg) << endl;
1443 for (pkgCache::VerFileIterator VF = V.FileList(); VF.end() == false; VF++)
1444 {
1445 // Locate the associated index files so we can derive a description
1446 pkgIndexFile *Indx;
1447 if (SrcList->FindIndex(VF.File(),Indx) == false &&
1448 _system->FindIndex(VF.File(),Indx) == false)
1449 return _error->Error(_("Cache is out of sync, can't x-ref a package file"));
1450 printf(_(" %4i %s\n"),Plcy.GetPriority(VF.File()),
1451 Indx->Describe(true).c_str());
1452 }
1453 }
1454 }
1455
f8f410f5
AL
1456 return true;
1457}
1458 /*}}}*/
880e9be4
AL
1459// GenCaches - Call the main cache generator /*{{{*/
1460// ---------------------------------------------------------------------
1461/* */
b0b4efb9 1462bool GenCaches(CommandLine &Cmd)
880e9be4 1463{
0a8e3465
AL
1464 OpTextProgress Progress(*_config);
1465
880e9be4 1466 pkgSourceList List;
b2e465d6
AL
1467 if (List.ReadMainList() == false)
1468 return false;
0a8e3465 1469 return pkgMakeStatusCache(List,Progress);
880e9be4
AL
1470}
1471 /*}}}*/
e1b74f61
AL
1472// ShowHelp - Show a help screen /*{{{*/
1473// ---------------------------------------------------------------------
1474/* */
b0b4efb9 1475bool ShowHelp(CommandLine &Cmd)
e1b74f61 1476{
b2e465d6
AL
1477 ioprintf(cout,_("%s %s for %s %s compiled on %s %s\n"),PACKAGE,VERSION,
1478 COMMON_OS,COMMON_CPU,__DATE__,__TIME__);
e1b74f61 1479
b2e465d6
AL
1480 cout <<
1481 _("Usage: apt-cache [options] command\n"
1482 " apt-cache [options] add file1 [file1 ...]\n"
1483 " apt-cache [options] showpkg pkg1 [pkg2 ...]\n"
2d425135 1484 " apt-cache [options] showsrc pkg1 [pkg2 ...]\n"
b2e465d6
AL
1485 "\n"
1486 "apt-cache is a low-level tool used to manipulate APT's binary\n"
1487 "cache files, and query information from them\n"
1488 "\n"
1489 "Commands:\n"
bac2e715 1490 " add - Add a package file to the source cache\n"
b2e465d6
AL
1491 " gencaches - Build both the package and source cache\n"
1492 " showpkg - Show some general information for a single package\n"
2d425135 1493 " showsrc - Show source records\n"
b2e465d6
AL
1494 " stats - Show some basic statistics\n"
1495 " dump - Show the entire file in a terse form\n"
1496 " dumpavail - Print an available file to stdout\n"
1497 " unmet - Show unmet dependencies\n"
b2e465d6
AL
1498 " search - Search the package list for a regex pattern\n"
1499 " show - Show a readable record for the package\n"
1500 " depends - Show raw dependency information for a package\n"
1501 " pkgnames - List the names of all packages\n"
1502 " dotty - Generate package graphs for GraphVis\n"
fff4b7f3 1503 " xvcg - Generate package graphs for xvcg\n"
eba05d54 1504 " policy - Show policy settings\n"
b2e465d6
AL
1505 "\n"
1506 "Options:\n"
1507 " -h This help text.\n"
1508 " -p=? The package cache.\n"
1509 " -s=? The source cache.\n"
1510 " -q Disable progress indicator.\n"
1511 " -i Show only important deps for the unmet command.\n"
1512 " -c=? Read this configuration file\n"
1513 " -o=? Set an arbitary configuration option, eg -o dir::cache=/tmp\n"
1514 "See the apt-cache(8) and apt.conf(5) manual pages for more information.\n");
1515 return true;
e1b74f61
AL
1516}
1517 /*}}}*/
0a8e3465
AL
1518// CacheInitialize - Initialize things for apt-cache /*{{{*/
1519// ---------------------------------------------------------------------
1520/* */
1521void CacheInitialize()
1522{
1523 _config->Set("quiet",0);
1524 _config->Set("help",false);
1525}
1526 /*}}}*/
1164783d 1527
08e8f724 1528int main(int argc,const char *argv[])
1164783d 1529{
08e8f724
AL
1530 CommandLine::Args Args[] = {
1531 {'h',"help","help",0},
04aa15a8 1532 {'v',"version","version",0},
e1b74f61
AL
1533 {'p',"pkg-cache","Dir::Cache::pkgcache",CommandLine::HasArg},
1534 {'s',"src-cache","Dir::Cache::srcpkgcache",CommandLine::HasArg},
1535 {'q',"quiet","quiet",CommandLine::IntLevel},
76fbce56 1536 {'i',"important","APT::Cache::Important",0},
7e2e2d5d 1537 {'f',"full","APT::Cache::ShowFull",0},
b2e465d6 1538 {'g',"generate","APT::Cache::Generate",0},
648e3cb4 1539 {'a',"all-versions","APT::Cache::AllVersions",0},
7e2e2d5d 1540 {0,"names-only","APT::Cache::NamesOnly",0},
03eb0ddc 1541 {'n',"all-names","APT::Cache::AllNames",0},
b2e465d6 1542 {0,"recurse","APT::Cache::RecurseDepends",0},
e1b74f61
AL
1543 {'c',"config-file",0,CommandLine::ConfigFile},
1544 {'o',"option",0,CommandLine::ArbItem},
08e8f724 1545 {0,0,0,0}};
b0b4efb9
AL
1546 CommandLine::Dispatch CmdsA[] = {{"help",&ShowHelp},
1547 {"add",&DoAdd},
1548 {"gencaches",&GenCaches},
f8f410f5 1549 {"showsrc",&ShowSrcPackage},
b0b4efb9
AL
1550 {0,0}};
1551 CommandLine::Dispatch CmdsB[] = {{"showpkg",&DumpPackage},
1552 {"stats",&Stats},
1553 {"dump",&Dump},
1554 {"dumpavail",&DumpAvail},
1555 {"unmet",&UnMet},
9dbb421f 1556 {"search",&Search},
349cd3b8 1557 {"depends",&Depends},
3e94da1b 1558 {"dotty",&Dotty},
fff4b7f3 1559 {"xvcg",&XVcg},
7e2e2d5d 1560 {"show",&ShowPackage},
7c1133fe 1561 {"pkgnames",&ShowPkgNames},
af87ab54 1562 {"policy",&Policy},
b0b4efb9 1563 {0,0}};
0a8e3465
AL
1564
1565 CacheInitialize();
67111687
AL
1566
1567 // Set up gettext support
1568 setlocale(LC_ALL,"");
1569 textdomain(PACKAGE);
1570
e1b74f61
AL
1571 // Parse the command line and initialize the package library
1572 CommandLine CmdL(Args,_config);
b2e465d6
AL
1573 if (pkgInitConfig(*_config) == false ||
1574 CmdL.Parse(argc,argv) == false ||
1575 pkgInitSystem(*_config,_system) == false)
08e8f724
AL
1576 {
1577 _error->DumpErrors();
1578 return 100;
1164783d 1579 }
8efa2a3b 1580
e1b74f61
AL
1581 // See if the help should be shown
1582 if (_config->FindB("help") == true ||
1583 CmdL.FileSize() == 0)
b2e465d6
AL
1584 {
1585 ShowHelp(CmdL);
1586 return 0;
1587 }
1588
a9a5908d
AL
1589 // Deal with stdout not being a tty
1590 if (ttyname(STDOUT_FILENO) == 0 && _config->FindI("quiet",0) < 1)
1591 _config->Set("quiet","1");
1592
b0b4efb9 1593 if (CmdL.DispatchArg(CmdsA,false) == false && _error->PendingError() == false)
4b1b89c5 1594 {
2a3f3893 1595 MMap *Map = 0;
b2e465d6 1596 if (_config->FindB("APT::Cache::Generate",true) == false)
4b1b89c5
AL
1597 {
1598 Map = new MMap(*new FileFd(_config->FindFile("Dir::Cache::pkgcache"),
1599 FileFd::ReadOnly),MMap::Public|MMap::ReadOnly);
1600 }
1601 else
1602 {
1603 // Open the cache file
af87ab54
AL
1604 SrcList = new pkgSourceList;
1605 SrcList->ReadMainList();
f8f410f5 1606
4b1b89c5
AL
1607 // Generate it and map it
1608 OpProgress Prog;
af87ab54 1609 pkgMakeStatusCache(*SrcList,Prog,&Map,true);
4b1b89c5
AL
1610 }
1611
b0b4efb9 1612 if (_error->PendingError() == false)
1164783d 1613 {
b2e465d6 1614 pkgCache Cache(Map);
b0b4efb9
AL
1615 GCache = &Cache;
1616 if (_error->PendingError() == false)
1617 CmdL.DispatchArg(CmdsB);
803fafcb
AL
1618 }
1619 delete Map;
1164783d
AL
1620 }
1621
1622 // Print any errors or warnings found during parsing
1623 if (_error->empty() == false)
1624 {
0a8e3465 1625 bool Errors = _error->PendingError();
1164783d 1626 _error->DumpErrors();
0a8e3465 1627 return Errors == true?100:0;
1164783d
AL
1628 }
1629
1630 return 0;
1631}