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