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