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