Purge support
[ntk/apt.git] / apt-pkg / depcache.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: depcache.cc,v 1.19 1999/07/10 04:58:42 jgg Exp $
4 /* ######################################################################
5
6 Dependency Cache - Caches Dependency information.
7
8 ##################################################################### */
9 /*}}}*/
10 // Include Files /*{{{*/
11 #ifdef __GNUG__
12 #pragma implementation "apt-pkg/depcache.h"
13 #endif
14 #include <apt-pkg/depcache.h>
15
16 #include <apt-pkg/version.h>
17 #include <apt-pkg/error.h>
18 /*}}}*/
19
20 // DepCache::pkgDepCache - Constructors /*{{{*/
21 // ---------------------------------------------------------------------
22 /* */
23 pkgDepCache::pkgDepCache(MMap &Map,OpProgress &Prog) :
24 pkgCache(Map), PkgState(0), DepState(0)
25 {
26 if (_error->PendingError() == false)
27 Init(&Prog);
28 }
29 pkgDepCache::pkgDepCache(MMap &Map) :
30 pkgCache(Map), PkgState(0), DepState(0)
31 {
32 if (_error->PendingError() == false)
33 Init(0);
34 }
35 /*}}}*/
36 // DepCache::~pkgDepCache - Destructor /*{{{*/
37 // ---------------------------------------------------------------------
38 /* */
39 pkgDepCache::~pkgDepCache()
40 {
41 delete [] PkgState;
42 delete [] DepState;
43 }
44 /*}}}*/
45 // DepCache::Init - Generate the initial extra structures. /*{{{*/
46 // ---------------------------------------------------------------------
47 /* This allocats the extension buffers and initializes them. */
48 bool pkgDepCache::Init(OpProgress *Prog)
49 {
50 delete [] PkgState;
51 delete [] DepState;
52 PkgState = new StateCache[Head().PackageCount];
53 DepState = new unsigned char[Head().DependsCount];
54 memset(PkgState,0,sizeof(*PkgState)*Head().PackageCount);
55 memset(DepState,0,sizeof(*DepState)*Head().DependsCount);
56
57 if (Prog != 0)
58 {
59 Prog->OverallProgress(0,2*Head().PackageCount,Head().PackageCount,
60 "Building Dependency Tree");
61 Prog->SubProgress(Head().PackageCount,"Candidate Versions");
62 }
63
64 /* Set the current state of everything. In this state all of the
65 packages are kept exactly as is. See AllUpgrade */
66 int Done = 0;
67 for (PkgIterator I = PkgBegin(); I.end() != true; I++,Done++)
68 {
69 if (Prog != 0)
70 Prog->Progress(Done);
71
72 // Find the proper cache slot
73 StateCache &State = PkgState[I->ID];
74 State.iFlags = 0;
75
76 // Figure out the install version
77 State.CandidateVer = GetCandidateVer(I);
78 State.InstallVer = I.CurrentVer();
79 State.Mode = ModeKeep;
80
81 State.Update(I,*this);
82 }
83
84 if (Prog != 0)
85 {
86
87 Prog->OverallProgress(Head().PackageCount,2*Head().PackageCount,
88 Head().PackageCount,
89 "Building Dependency Tree");
90 Prog->SubProgress(Head().PackageCount,"Dependency Generation");
91 }
92
93 Update(Prog);
94
95 return true;
96 }
97 /*}}}*/
98 // DepCache::GetCandidateVer - Returns the Candidate install version /*{{{*/
99 // ---------------------------------------------------------------------
100 /* The default just returns the target version if it exists or the
101 highest version. */
102 pkgDepCache::VerIterator pkgDepCache::GetCandidateVer(PkgIterator Pkg,
103 bool AllowCurrent)
104 {
105 // Try to use an explicit target
106 if (Pkg->TargetVer == 0 ||
107 (AllowCurrent == false && Pkg.TargetVer() == Pkg.CurrentVer()))
108 return pkgCache::GetCandidateVer(Pkg,AllowCurrent);
109 else
110 return Pkg.TargetVer();
111 }
112 /*}}}*/
113 // DepCache::IsImportantDep - True if the dependency is important /*{{{*/
114 // ---------------------------------------------------------------------
115 /* */
116 bool pkgDepCache::IsImportantDep(DepIterator Dep)
117 {
118 return Dep.IsCritical();
119 }
120 /*}}}*/
121
122 // DepCache::CheckDep - Checks a single dependency /*{{{*/
123 // ---------------------------------------------------------------------
124 /* This first checks the dependency against the main target package and
125 then walks along the package provides list and checks if each provides
126 will be installed then checks the provides against the dep. Res will be
127 set to the package which was used to satisfy the dep. */
128 bool pkgDepCache::CheckDep(DepIterator Dep,int Type,PkgIterator &Res)
129 {
130 Res = Dep.TargetPkg();
131
132 /* Check simple depends. A depends -should- never self match but
133 we allow it anyhow because dpkg does. Technically it is a packaging
134 bug. Conflicts may never self match */
135 if (Dep.TargetPkg() != Dep.ParentPkg() || Dep->Type != Dep::Conflicts)
136 {
137 PkgIterator Pkg = Dep.TargetPkg();
138 // Check the base package
139 if (Type == NowVersion && Pkg->CurrentVer != 0)
140 if (pkgCheckDep(Dep.TargetVer(),
141 Pkg.CurrentVer().VerStr(),Dep->CompareOp) == true)
142 return true;
143
144 if (Type == InstallVersion && PkgState[Pkg->ID].InstallVer != 0)
145 if (pkgCheckDep(Dep.TargetVer(),
146 PkgState[Pkg->ID].InstVerIter(*this).VerStr(),
147 Dep->CompareOp) == true)
148 return true;
149
150 if (Type == CandidateVersion && PkgState[Pkg->ID].CandidateVer != 0)
151 if (pkgCheckDep(Dep.TargetVer(),
152 PkgState[Pkg->ID].CandidateVerIter(*this).VerStr(),
153 Dep->CompareOp) == true)
154 return true;
155 }
156
157 // Check the providing packages
158 PrvIterator P = Dep.TargetPkg().ProvidesList();
159 PkgIterator Pkg = Dep.ParentPkg();
160 for (; P.end() != true; P++)
161 {
162 /* Provides may never be applied against the same package if it is
163 a conflicts. See the comment above. */
164 if (P.OwnerPkg() == Pkg && Dep->Type == Dep::Conflicts)
165 continue;
166
167 // Check if the provides is a hit
168 if (Type == NowVersion)
169 {
170 if (P.OwnerPkg().CurrentVer() != P.OwnerVer())
171 continue;
172 }
173
174 if (Type == InstallVersion)
175 {
176 StateCache &State = PkgState[P.OwnerPkg()->ID];
177 if (State.InstallVer != (Version *)P.OwnerVer())
178 continue;
179 }
180
181 if (Type == CandidateVersion)
182 {
183 StateCache &State = PkgState[P.OwnerPkg()->ID];
184 if (State.CandidateVer != (Version *)P.OwnerVer())
185 continue;
186 }
187
188 // Compare the versions.
189 if (pkgCheckDep(Dep.TargetVer(),P.ProvideVersion(),Dep->CompareOp) == true)
190 {
191 Res = P.OwnerPkg();
192 return true;
193 }
194 }
195
196 return false;
197 }
198 /*}}}*/
199 // DepCache::AddSizes - Add the packages sizes to the counters /*{{{*/
200 // ---------------------------------------------------------------------
201 /* Call with Mult = -1 to preform the inverse opration */
202 void pkgDepCache::AddSizes(const PkgIterator &Pkg,long Mult)
203 {
204 StateCache &P = PkgState[Pkg->ID];
205
206 if (Pkg.State() == pkgCache::PkgIterator::NeedsConfigure &&
207 P.Keep() == true)
208 return;
209
210 // Compute the size data
211 if (P.NewInstall() == true)
212 {
213 iUsrSize += Mult*P.InstVerIter(*this)->InstalledSize;
214 iDownloadSize += Mult*P.InstVerIter(*this)->Size;
215 return;
216 }
217
218 // Upgrading
219 if (Pkg->CurrentVer != 0 && P.InstallVer != (Version *)Pkg.CurrentVer() &&
220 P.InstallVer != 0)
221 {
222 iUsrSize += Mult*((signed)P.InstVerIter(*this)->InstalledSize -
223 (signed)Pkg.CurrentVer()->InstalledSize);
224 iDownloadSize += Mult*P.InstVerIter(*this)->Size;
225 return;
226 }
227
228 // Reinstall
229 if (Pkg.State() == pkgCache::PkgIterator::NeedsUnpack &&
230 P.Delete() == false)
231 {
232 iDownloadSize += Mult*P.InstVerIter(*this)->Size;
233 return;
234 }
235
236 // Removing
237 if (Pkg->CurrentVer != 0 && P.InstallVer == 0)
238 {
239 iUsrSize -= Mult*Pkg.CurrentVer()->InstalledSize;
240 return;
241 }
242 }
243 /*}}}*/
244 // DepCache::AddStates - Add the package to the state counter /*{{{*/
245 // ---------------------------------------------------------------------
246 /* This routine is tricky to use, you must make sure that it is never
247 called twice for the same package. This means the Remove/Add section
248 should be as short as possible and not encompass any code that will
249 calld Remove/Add itself. Remember, dependencies can be circular so
250 while processing a dep for Pkg it is possible that Add/Remove
251 will be called on Pkg */
252 void pkgDepCache::AddStates(const PkgIterator &Pkg,int Add)
253 {
254 StateCache &State = PkgState[Pkg->ID];
255
256 // The Package is broken
257 if ((State.DepState & DepInstMin) != DepInstMin)
258 iBrokenCount += Add;
259
260 // Bad state
261 if (Pkg.State() != PkgIterator::NeedsNothing)
262 iBadCount += Add;
263
264 // Not installed
265 if (Pkg->CurrentVer == 0)
266 {
267 if (State.Mode == ModeDelete &&
268 (State.iFlags | Purge) == Purge && Pkg.Purge() == false)
269 iDelCount += Add;
270
271 if (State.Mode == ModeInstall)
272 iInstCount += Add;
273 return;
274 }
275
276 // Installed, no upgrade
277 if (State.Upgradable() == false)
278 {
279 if (State.Mode == ModeDelete)
280 iDelCount += Add;
281 return;
282 }
283
284 // Alll 3 are possible
285 if (State.Mode == ModeDelete)
286 iDelCount += Add;
287 if (State.Mode == ModeKeep)
288 iKeepCount += Add;
289 if (State.Mode == ModeInstall)
290 iInstCount += Add;
291 }
292 /*}}}*/
293 // DepCache::BuildGroupOrs - Generate the Or group dep data /*{{{*/
294 // ---------------------------------------------------------------------
295 /* The or group results are stored in the last item of the or group. This
296 allows easy detection of the state of a whole or'd group. */
297 void pkgDepCache::BuildGroupOrs(VerIterator const &V)
298 {
299 unsigned char Group = 0;
300
301 for (DepIterator D = V.DependsList(); D.end() != true; D++)
302 {
303 // Build the dependency state.
304 unsigned char &State = DepState[D->ID];
305
306 /* Invert for Conflicts. We have to do this twice to get the
307 right sense for a conflicts group */
308 if (D->Type == Dep::Conflicts)
309 State = ~State;
310
311 // Add to the group if we are within an or..
312 State &= 0x7;
313 Group |= State;
314 State |= Group << 3;
315 if ((D->CompareOp & Dep::Or) != Dep::Or)
316 Group = 0;
317
318 // Invert for Conflicts
319 if (D->Type == Dep::Conflicts)
320 State = ~State;
321 }
322 }
323 /*}}}*/
324 // DepCache::VersionState - Perform a pass over a dependency list /*{{{*/
325 // ---------------------------------------------------------------------
326 /* This is used to run over a dependency list and determine the dep
327 state of the list, filtering it through both a Min check and a Policy
328 check. The return result will have SetMin/SetPolicy low if a check
329 fails. It uses the DepState cache for it's computations. */
330 unsigned char pkgDepCache::VersionState(DepIterator D,unsigned char Check,
331 unsigned char SetMin,
332 unsigned char SetPolicy)
333 {
334 unsigned char Dep = 0xFF;
335
336 while (D.end() != true)
337 {
338 // Compute a single dependency element (glob or)
339 DepIterator Start = D;
340 unsigned char State = 0;
341 for (bool LastOR = true; D.end() == false && LastOR == true; D++)
342 {
343 State |= DepState[D->ID];
344 LastOR = (D->CompareOp & Dep::Or) == Dep::Or;
345 }
346
347 // Minimum deps that must be satisfied to have a working package
348 if (Start.IsCritical() == true)
349 if ((State & Check) != Check)
350 Dep &= ~SetMin;
351
352 // Policy deps that must be satisfied to install the package
353 if (IsImportantDep(Start) == true &&
354 (State & Check) != Check)
355 Dep &= ~SetPolicy;
356 }
357
358 return Dep;
359 }
360 /*}}}*/
361 // DepCache::DependencyState - Compute the 3 results for a dep /*{{{*/
362 // ---------------------------------------------------------------------
363 /* This is the main dependency computation bit. It computes the 3 main
364 results for a dependencys, Now, Install and Candidate. Callers must
365 invert the result if dealing with conflicts. */
366 unsigned char pkgDepCache::DependencyState(DepIterator &D)
367 {
368 unsigned char State = 0;
369
370 if (CheckDep(D,NowVersion) == true)
371 State |= DepNow;
372 if (CheckDep(D,InstallVersion) == true)
373 State |= DepInstall;
374 if (CheckDep(D,CandidateVersion) == true)
375 State |= DepCVer;
376
377 return State;
378 }
379 /*}}}*/
380 // DepCache::UpdateVerState - Compute the Dep member of the state /*{{{*/
381 // ---------------------------------------------------------------------
382 /* This determines the combined dependency representation of a package
383 for its two states now and install. This is done by using the pre-generated
384 dependency information. */
385 void pkgDepCache::UpdateVerState(PkgIterator Pkg)
386 {
387 // Empty deps are always true
388 StateCache &State = PkgState[Pkg->ID];
389 State.DepState = 0xFF;
390
391 // Check the Current state
392 if (Pkg->CurrentVer != 0)
393 {
394 DepIterator D = Pkg.CurrentVer().DependsList();
395 State.DepState &= VersionState(D,DepNow,DepNowMin,DepNowPolicy);
396 }
397
398 /* Check the candidate state. We do not compare against the whole as
399 a candidate state but check the candidate version against the
400 install states */
401 if (State.CandidateVer != 0)
402 {
403 DepIterator D = State.CandidateVerIter(*this).DependsList();
404 State.DepState &= VersionState(D,DepInstall,DepCandMin,DepCandPolicy);
405 }
406
407 // Check target state which can only be current or installed
408 if (State.InstallVer != 0)
409 {
410 DepIterator D = State.InstVerIter(*this).DependsList();
411 State.DepState &= VersionState(D,DepInstall,DepInstMin,DepInstPolicy);
412 }
413 }
414 /*}}}*/
415 // DepCache::Update - Figure out all the state information /*{{{*/
416 // ---------------------------------------------------------------------
417 /* This will figure out the state of all the packages and all the
418 dependencies based on the current policy. */
419 void pkgDepCache::Update(OpProgress *Prog)
420 {
421 iUsrSize = 0;
422 iDownloadSize = 0;
423 iDelCount = 0;
424 iInstCount = 0;
425 iKeepCount = 0;
426 iBrokenCount = 0;
427 iBadCount = 0;
428
429 // Perform the depends pass
430 int Done = 0;
431 for (PkgIterator I = PkgBegin(); I.end() != true; I++,Done++)
432 {
433 if (Prog != 0 && Done%20 == 0)
434 Prog->Progress(Done);
435 for (VerIterator V = I.VersionList(); V.end() != true; V++)
436 {
437 unsigned char Group = 0;
438
439 for (DepIterator D = V.DependsList(); D.end() != true; D++)
440 {
441 // Build the dependency state.
442 unsigned char &State = DepState[D->ID];
443 State = DependencyState(D);;
444
445 // Add to the group if we are within an or..
446 Group |= State;
447 State |= Group << 3;
448 if ((D->CompareOp & Dep::Or) != Dep::Or)
449 Group = 0;
450
451 // Invert for Conflicts
452 if (D->Type == Dep::Conflicts)
453 State = ~State;
454 }
455 }
456
457 // Compute the pacakge dependency state and size additions
458 AddSizes(I);
459 UpdateVerState(I);
460 AddStates(I);
461 }
462
463 if (Prog != 0)
464 Prog->Progress(Done);
465 }
466 /*}}}*/
467 // DepCache::Update - Update the deps list of a package /*{{{*/
468 // ---------------------------------------------------------------------
469 /* This is a helper for update that only does the dep portion of the scan.
470 It is mainly ment to scan reverse dependencies. */
471 void pkgDepCache::Update(DepIterator D)
472 {
473 // Update the reverse deps
474 for (;D.end() != true; D++)
475 {
476 unsigned char &State = DepState[D->ID];
477 State = DependencyState(D);
478
479 // Invert for Conflicts
480 if (D->Type == Dep::Conflicts)
481 State = ~State;
482
483 RemoveStates(D.ParentPkg());
484 BuildGroupOrs(D.ParentVer());
485 UpdateVerState(D.ParentPkg());
486 AddStates(D.ParentPkg());
487 }
488 }
489 /*}}}*/
490 // DepCache::Update - Update the related deps of a package /*{{{*/
491 // ---------------------------------------------------------------------
492 /* This is called whenever the state of a package changes. It updates
493 all cached dependencies related to this package. */
494 void pkgDepCache::Update(PkgIterator const &Pkg)
495 {
496 // Recompute the dep of the package
497 RemoveStates(Pkg);
498 UpdateVerState(Pkg);
499 AddStates(Pkg);
500
501 // Update the reverse deps
502 Update(Pkg.RevDependsList());
503
504 // Update the provides map for the current ver
505 if (Pkg->CurrentVer != 0)
506 for (PrvIterator P = Pkg.CurrentVer().ProvidesList();
507 P.end() != true; P++)
508 Update(P.ParentPkg().RevDependsList());
509
510 // Update the provides map for the candidate ver
511 for (PrvIterator P = PkgState[Pkg->ID].CandidateVerIter(*this).ProvidesList();
512 P.end() != true; P++)
513 Update(P.ParentPkg().RevDependsList());
514 }
515
516 /*}}}*/
517
518 // DepCache::MarkKeep - Put the package in the keep state /*{{{*/
519 // ---------------------------------------------------------------------
520 /* */
521 void pkgDepCache::MarkKeep(PkgIterator const &Pkg,bool Soft)
522 {
523 // Simplifies other routines.
524 if (Pkg.end() == true)
525 return;
526
527 /* Reject an attempt to keep a non-source broken installed package, those
528 must be upgraded */
529 if (Pkg.State() == PkgIterator::NeedsUnpack &&
530 Pkg.CurrentVer().Downloadable() == false)
531 return;
532
533 /* We changed the soft state all the time so the UI is a bit nicer
534 to use */
535 StateCache &P = PkgState[Pkg->ID];
536 if (Soft == true)
537 P.iFlags |= AutoKept;
538 else
539 P.iFlags &= ~AutoKept;
540
541 // Check that it is not already kept
542 if (P.Mode == ModeKeep)
543 return;
544
545 // We dont even try to keep virtual packages..
546 if (Pkg->VersionList == 0)
547 return;
548
549 P.Flags &= ~Flag::Auto;
550 RemoveSizes(Pkg);
551 RemoveStates(Pkg);
552
553 P.Mode = ModeKeep;
554 if (Pkg->CurrentVer == 0)
555 P.InstallVer = 0;
556 else
557 P.InstallVer = Pkg.CurrentVer();
558
559 AddStates(Pkg);
560
561 Update(Pkg);
562
563 AddSizes(Pkg);
564 }
565 /*}}}*/
566 // DepCache::MarkDelete - Put the package in the delete state /*{{{*/
567 // ---------------------------------------------------------------------
568 /* */
569 void pkgDepCache::MarkDelete(PkgIterator const &Pkg, bool rPurge)
570 {
571 // Simplifies other routines.
572 if (Pkg.end() == true)
573 return;
574
575 // Check that it is not already marked for delete
576 StateCache &P = PkgState[Pkg->ID];
577 P.iFlags &= ~(AutoKept | Purge);
578 if (rPurge == true)
579 P.iFlags |= Purge;
580
581 if ((P.Mode == ModeDelete || P.InstallVer == 0) &&
582 (Pkg.Purge() == true || rPurge == false))
583 return;
584
585 // We dont even try to delete virtual packages..
586 if (Pkg->VersionList == 0)
587 return;
588
589 RemoveSizes(Pkg);
590 RemoveStates(Pkg);
591
592 if (Pkg->CurrentVer == 0 && (Pkg.Purge() == true || rPurge == false))
593 P.Mode = ModeKeep;
594 else
595 P.Mode = ModeDelete;
596 P.InstallVer = 0;
597 P.Flags &= Flag::Auto;
598
599 AddStates(Pkg);
600 Update(Pkg);
601 AddSizes(Pkg);
602 }
603 /*}}}*/
604 // DepCache::MarkInstall - Put the package in the install state /*{{{*/
605 // ---------------------------------------------------------------------
606 /* */
607 void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst)
608 {
609 // Simplifies other routines.
610 if (Pkg.end() == true)
611 return;
612
613 /* Check that it is not already marked for install and that it can be
614 installed */
615 StateCache &P = PkgState[Pkg->ID];
616 P.iFlags &= ~AutoKept;
617 if (P.InstBroken() == false && (P.Mode == ModeInstall ||
618 P.CandidateVer == (Version *)Pkg.CurrentVer()))
619 {
620 if (P.CandidateVer == (Version *)Pkg.CurrentVer() && P.InstallVer == 0)
621 MarkKeep(Pkg);
622 return;
623 }
624
625 // We dont even try to install virtual packages..
626 if (Pkg->VersionList == 0)
627 return;
628
629 /* Target the candidate version and remove the autoflag. We reset the
630 autoflag below if this was called recursively. Otherwise the user
631 should have the ability to de-auto a package by changing its state */
632 RemoveSizes(Pkg);
633 RemoveStates(Pkg);
634
635 P.Mode = ModeInstall;
636 P.InstallVer = P.CandidateVer;
637 P.Flags &= ~Flag::Auto;
638 if (P.CandidateVer == (Version *)Pkg.CurrentVer())
639 P.Mode = ModeKeep;
640
641 AddStates(Pkg);
642 Update(Pkg);
643 AddSizes(Pkg);
644
645 if (AutoInst == false)
646 return;
647
648 DepIterator Dep = P.InstVerIter(*this).DependsList();
649 for (; Dep.end() != true;)
650 {
651 // Grok or groups
652 DepIterator Start = Dep;
653 bool Result = true;
654 for (bool LastOR = true; Dep.end() == false && LastOR == true; Dep++)
655 {
656 LastOR = (Dep->CompareOp & Dep::Or) == Dep::Or;
657
658 if ((DepState[Dep->ID] & DepInstall) == DepInstall)
659 Result = false;
660 }
661
662 // Dep is satisfied okay.
663 if (Result == false)
664 continue;
665
666 /* Check if this dep should be consider for install. If it is a user
667 defined important dep and we are installed a new package then
668 it will be installed. Otherwise we only worry about critical deps */
669 if (IsImportantDep(Start) == false)
670 continue;
671 if (Pkg->CurrentVer != 0 && Start.IsCritical() == false)
672 continue;
673
674 // Now we have to take action...
675 PkgIterator P = Start.SmartTargetPkg();
676 if ((DepState[Start->ID] & DepCVer) == DepCVer)
677 {
678 MarkInstall(P,true);
679
680 // Set the autoflag, after MarkInstall because MarkInstall unsets it
681 if (P->CurrentVer == 0)
682 PkgState[P->ID].Flags |= Flag::Auto;
683
684 continue;
685 }
686
687 // For conflicts we just de-install the package and mark as auto
688 if (Start->Type == Dep::Conflicts)
689 {
690 Version **List = Start.AllTargets();
691 for (Version **I = List; *I != 0; I++)
692 {
693 VerIterator Ver(*this,*I);
694 PkgIterator Pkg = Ver.ParentPkg();
695
696 MarkDelete(Pkg);
697 PkgState[Pkg->ID].Flags |= Flag::Auto;
698 }
699 delete [] List;
700 continue;
701 }
702 }
703 }
704 /*}}}*/
705
706 // StateCache::Update - Compute the various static display things /*{{{*/
707 // ---------------------------------------------------------------------
708 /* This is called whenever the Candidate version changes. */
709 void pkgDepCache::StateCache::Update(PkgIterator Pkg,pkgCache &Cache)
710 {
711 // Some info
712 VerIterator Ver = CandidateVerIter(Cache);
713
714 // Use a null string or the version string
715 if (Ver.end() == true)
716 CandVersion = "";
717 else
718 CandVersion = Ver.VerStr();
719
720 // Find the current version
721 CurVersion = "";
722 if (Pkg->CurrentVer != 0)
723 CurVersion = Pkg.CurrentVer().VerStr();
724
725 // Strip off the epochs for display
726 CurVersion = StripEpoch(CurVersion);
727 CandVersion = StripEpoch(CandVersion);
728
729 // Figure out if its up or down or equal
730 Status = Ver.CompareVer(Pkg.CurrentVer());
731 if (Pkg->CurrentVer == 0 || Pkg->VersionList == 0 || CandidateVer == 0)
732 Status = 2;
733 }
734 /*}}}*/
735 // StateCache::StripEpoch - Remove the epoch specifier from the version /*{{{*/
736 // ---------------------------------------------------------------------
737 /* */
738 const char *pkgDepCache::StateCache::StripEpoch(const char *Ver)
739 {
740 if (Ver == 0)
741 return 0;
742
743 // Strip any epoch
744 for (const char *I = Ver; *I != 0; I++)
745 if (*I == ':')
746 return I + 1;
747 return Ver;
748 }
749 /*}}}*/