summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArch Librarian <arch@canonical.com>2004-09-20 16:50:41 +0000
committerArch Librarian <arch@canonical.com>2004-09-20 16:50:41 +0000
commit6c139d6e362f04a1582e8a8f511f8aeab031fecf (patch)
treec200b8f51da9bcfe612b7ceb645e6eec9ebac9f1
parent2246928b428c3ece2c2743da5b0bb63257e37a85 (diff)
Sync
Author: jgg Date: 1998-07-07 04:17:00 GMT Sync
-rw-r--r--apt-pkg/algorithms.cc732
-rw-r--r--apt-pkg/algorithms.h91
-rw-r--r--apt-pkg/cacheiterators.h21
-rw-r--r--apt-pkg/contrib/configuration.cc137
-rw-r--r--apt-pkg/contrib/configuration.h61
-rw-r--r--apt-pkg/contrib/error.cc74
-rw-r--r--apt-pkg/contrib/error.h15
-rw-r--r--apt-pkg/contrib/fileutl.cc5
-rw-r--r--apt-pkg/contrib/fileutl.h6
-rw-r--r--apt-pkg/contrib/mmap.cc6
-rw-r--r--apt-pkg/contrib/mmap.h6
-rw-r--r--apt-pkg/contrib/strutl.cc343
-rw-r--r--apt-pkg/contrib/strutl.h36
-rw-r--r--apt-pkg/deb/deblistparser.cc90
-rw-r--r--apt-pkg/depcache.cc903
-rw-r--r--apt-pkg/depcache.h189
-rw-r--r--apt-pkg/orderlist.cc829
-rw-r--r--apt-pkg/orderlist.h123
-rw-r--r--apt-pkg/packagemanager.cc548
-rw-r--r--apt-pkg/packagemanager.h84
-rw-r--r--apt-pkg/pkgcache.cc24
-rw-r--r--apt-pkg/pkgcache.h42
-rw-r--r--apt-pkg/pkgcachegen.cc6
-rw-r--r--apt-pkg/pkgcachegen.h6
-rw-r--r--apt-pkg/sourcelist.cc465
-rw-r--r--apt-pkg/sourcelist.h78
-rw-r--r--apt-pkg/tagfile.cc6
-rw-r--r--apt-pkg/tagfile.h6
-rw-r--r--apt-pkg/version.cc18
-rw-r--r--apt-pkg/version.h6
30 files changed, 4841 insertions, 115 deletions
diff --git a/apt-pkg/algorithms.cc b/apt-pkg/algorithms.cc
new file mode 100644
index 000000000..e3012489d
--- /dev/null
+++ b/apt-pkg/algorithms.cc
@@ -0,0 +1,732 @@
+// -*- mode: cpp; mode: fold -*-
+// Description /*{{{*/
+// $Id: algorithms.cc,v 1.1 1998/07/07 04:17:00 jgg Exp $
+/* ######################################################################
+
+ Algorithms - A set of misc algorithms
+
+ ##################################################################### */
+ /*}}}*/
+// Include Files /*{{{*/
+#ifdef __GNUG__
+#pragma implementation "pkglib/algorithms.h"
+#endif
+#include <pkglib/algorithms.h>
+#include <pkglib/error.h>
+#include <pkglib/pkgelement.h>
+#include <iostream.h>
+ /*}}}*/
+
+pkgProblemResolver *pkgProblemResolver::This = 0;
+
+// Simulate::Simulate - Constructor /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+pkgSimulate::pkgSimulate(pkgDepCache &Cache) : pkgPackageManager(Cache),
+ Sim(true,true)
+{
+ Flags = new unsigned char[Cache.HeaderP->PackageCount];
+ memset(Flags,0,sizeof(*Flags)*Cache.HeaderP->PackageCount);
+}
+ /*}}}*/
+// Simulate::Install - Simulate unpacking of a package /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool pkgSimulate::Install(PkgIterator iPkg,string /*File*/)
+{
+ // Adapt the iterator
+ PkgIterator Pkg = Sim.FindPkg(iPkg.Name());
+ Flags[Pkg->ID] = 1;
+
+ cout << "Inst " << Pkg.Name();
+ Sim.MarkInstall(Pkg,false);
+
+ // Look for broken conflicts+predepends.
+ for (PkgIterator I = Sim.PkgBegin(); I.end() == false; I++)
+ {
+ if (Sim[I].InstallVer == 0)
+ continue;
+
+ for (DepIterator D = Sim[I].InstVerIter(Sim).DependsList(); D.end() == false; D++)
+ if (D->Type == pkgDEP_Conflicts || D->Type == pkgDEP_PreDepends)
+ {
+ if ((Sim[D] & pkgDepCache::DepInstall) == 0)
+ {
+ cout << " [" << I.Name() << " on " << D.TargetPkg().Name() << ']';
+ if (D->Type == pkgDEP_Conflicts)
+ _error->Error("Fatal, conflicts violated %s",I.Name());
+ }
+ }
+ }
+
+ if (Sim.BrokenCount() != 0)
+ ShortBreaks();
+ else
+ cout << endl;
+ return true;
+}
+ /*}}}*/
+// Simulate::Configure - Simulate configuration of a Package /*{{{*/
+// ---------------------------------------------------------------------
+/* This is not an acurate simulation of relatity, we should really not
+ install the package.. For some investigations it may be necessary
+ however. */
+bool pkgSimulate::Configure(PkgIterator iPkg)
+{
+ // Adapt the iterator
+ PkgIterator Pkg = Sim.FindPkg(iPkg.Name());
+
+ Flags[Pkg->ID] = 2;
+// Sim.MarkInstall(Pkg,false);
+ if (Sim[Pkg].InstBroken() == true)
+ {
+ cout << "Conf " << Pkg.Name() << " broken" << endl;
+
+ Sim.Update();
+
+ // Print out each package and the failed dependencies
+ for (pkgCache::DepIterator D = Sim[Pkg].InstVerIter(Sim).DependsList(); D.end() == false; D++)
+ {
+ if (Sim.IsImportantDep(D) == false ||
+ (Sim[D] & pkgDepCache::DepInstall) != 0)
+ continue;
+
+ if (D->Type == pkgDEP_Conflicts)
+ cout << " Conflicts:" << D.TargetPkg().Name();
+ else
+ cout << " Depends:" << D.TargetPkg().Name();
+ }
+ cout << endl;
+
+ _error->Error("Conf Broken %s",Pkg.Name());
+ }
+ else
+ cout << "Conf " << Pkg.Name();
+
+ if (Sim.BrokenCount() != 0)
+ ShortBreaks();
+ else
+ cout << endl;
+
+ return true;
+}
+ /*}}}*/
+// Simulate::Remove - Simulate the removal of a package /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool pkgSimulate::Remove(PkgIterator iPkg)
+{
+ // Adapt the iterator
+ PkgIterator Pkg = Sim.FindPkg(iPkg.Name());
+
+ Flags[Pkg->ID] = 3;
+ Sim.MarkDelete(Pkg);
+ cout << "Remv " << Pkg.Name();
+
+ if (Sim.BrokenCount() != 0)
+ ShortBreaks();
+ else
+ cout << endl;
+
+ return true;
+}
+ /*}}}*/
+// Simulate::ShortBreaks - Print out a short line describing all breaks /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+void pkgSimulate::ShortBreaks()
+{
+ cout << " [";
+ for (PkgIterator I = Sim.PkgBegin(); I.end() == false; I++)
+ {
+ if (Sim[I].InstBroken() == true)
+ {
+ if (Flags[I->ID] == 0)
+ cout << I.Name() << ' ';
+/* else
+ cout << I.Name() << "! ";*/
+ }
+ }
+ cout << ']' << endl;
+}
+ /*}}}*/
+// ApplyStatus - Adjust for non-ok packages /*{{{*/
+// ---------------------------------------------------------------------
+/* We attempt to change the state of the all packages that have failed
+ installation toward their real state. The ordering code will perform
+ the necessary calculations to deal with the problems. */
+bool pkgApplyStatus(pkgDepCache &Cache)
+{
+ for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+ {
+ switch (I->CurrentState)
+ {
+ // This means installation failed somehow
+ case pkgSTATE_UnPacked:
+ case pkgSTATE_HalfConfigured:
+ Cache.MarkKeep(I);
+ break;
+
+ // This means removal failed
+ case pkgSTATE_HalfInstalled:
+ Cache.MarkDelete(I);
+ break;
+
+ default:
+ if (I->InstState != pkgSTATE_Ok)
+ return _error->Error("The package %s is not ok and I "
+ "don't know how to fix it!",I.Name());
+ }
+ }
+ return true;
+}
+ /*}}}*/
+// FixBroken - Fix broken packages /*{{{*/
+// ---------------------------------------------------------------------
+/* This autoinstalls every broken package and then runs ScoredFix on the
+ result. */
+bool pkgFixBroken(pkgDepCache &Cache)
+{
+ // Auto upgrade all broken packages
+ for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+ if (Cache[I].NowBroken() == true)
+ Cache.MarkInstall(I,true);
+
+ /* Fix packages that are in a NeedArchive state but don't have a
+ downloadable install version */
+ for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+ {
+ if (I.State() != pkgCache::PkgIterator::NeedsUnpack ||
+ Cache[I].Delete() == true)
+ continue;
+
+ if ((Cache[I].InstVerIter(Cache).File()->Flags & pkgFLAG_NotSource) == 0)
+ continue;
+
+ Cache.MarkInstall(I,true);
+ }
+
+ pkgProblemResolver Fix(Cache);
+ return Fix.Resolve(true);
+}
+ /*}}}*/
+// DistUpgrade - Distribution upgrade /*{{{*/
+// ---------------------------------------------------------------------
+/* This autoinstalls every package and then force installs every
+ pre-existing package. This creates the initial set of conditions which
+ most likely contain problems because too many things were installed.
+
+ ScoredFix is used to resolve the problems.
+ */
+bool pkgDistUpgrade(pkgDepCache &Cache)
+{
+ /* Auto upgrade all installed packages, this provides the basis
+ for the installation */
+ for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+ if (I->CurrentVer != 0)
+ Cache.MarkInstall(I,true);
+
+ /* Now, auto upgrade all essential packages - this ensures that
+ the essential packages are present and working */
+ for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+ if ((I->Flags & pkgFLAG_Essential) == pkgFLAG_Essential)
+ Cache.MarkInstall(I,true);
+
+ /* We do it again over all previously installed packages to force
+ conflict resolution on them all. */
+ for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+ if (I->CurrentVer != 0)
+ Cache.MarkInstall(I,false);
+
+ pkgProblemResolver Fix(Cache);
+
+ // Hold back held packages.
+ for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+ {
+ if (I->SelectedState == pkgSTATE_Hold)
+ {
+ Fix.Protect(I);
+ Cache.MarkKeep(I);
+ }
+ }
+
+ return Fix.Resolve();
+}
+ /*}}}*/
+
+// ProblemResolver::pkgProblemResolver - Constructor /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+pkgProblemResolver::pkgProblemResolver(pkgDepCache &Cache) : Cache(Cache)
+{
+ // Allocate memory
+ unsigned long Size = Cache.HeaderP->PackageCount;
+ Scores = new signed short[Size];
+ Flags = new unsigned char[Size];
+ memset(Flags,0,sizeof(*Flags)*Size);
+
+ // Set debug to true to see its decision logic
+ Debug = false;
+}
+ /*}}}*/
+// ProblemResolver::ScoreSort - Sort the list by score /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+int pkgProblemResolver::ScoreSort(const void *a,const void *b)
+{
+ Package const **A = (Package const **)a;
+ Package const **B = (Package const **)b;
+ if (This->Scores[(*A)->ID] > This->Scores[(*B)->ID])
+ return -1;
+ if (This->Scores[(*A)->ID] < This->Scores[(*B)->ID])
+ return 1;
+ return 0;
+}
+ /*}}}*/
+// ProblemResolver::MakeScores - Make the score table /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+void pkgProblemResolver::MakeScores()
+{
+ unsigned long Size = Cache.HeaderP->PackageCount;
+ memset(Scores,0,sizeof(*Scores)*Size);
+
+ // Generate the base scores for a package based on its properties
+ for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+ {
+ if (Cache[I].InstallVer == 0)
+ continue;
+
+ signed short &Score = Scores[I->ID];
+
+ /* This is arbitary, it should be high enough to elevate an
+ essantial package above most other packages but low enough
+ to allow an obsolete essential packages to be removed by
+ a conflicts on a powerfull normal package (ie libc6) */
+ if ((I->Flags & pkgFLAG_Essential) == pkgFLAG_Essential)
+ Score += 100;
+
+ // We transform the priority
+ // Important Required Standard Optional Extra
+ signed short PrioMap[] = {0,3,2,1,-1,-2};
+ if (Cache[I].InstVerIter(Cache)->Priority <= 5)
+ Score += PrioMap[Cache[I].InstVerIter(Cache)->Priority];
+
+ /* This helps to fix oddball problems with conflicting packages
+ on the same level. We enhance the score of installed packages */
+ if (I->CurrentVer != 0)
+ Score += 1;
+ }
+
+ // Now that we have the base scores we go and propogate dependencies
+ for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+ {
+ if (Cache[I].InstallVer == 0)
+ continue;
+
+ for (pkgCache::DepIterator D = Cache[I].InstVerIter(Cache).DependsList(); D.end() == false; D++)
+ {
+ if (D->Type == pkgDEP_Depends || D->Type == pkgDEP_PreDepends)
+ Scores[D.TargetPkg()->ID]++;
+ }
+ }
+
+ // Copy the scores to advoid additive looping
+ signed short *OldScores = new signed short[Size];
+ memcpy(OldScores,Scores,sizeof(*Scores)*Size);
+
+ /* Now we cause 1 level of dependency inheritance, that is we add the
+ score of the packages that depend on the target Package. This
+ fortifies high scoring packages */
+ for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+ {
+ if (Cache[I].InstallVer == 0)
+ continue;
+
+ for (pkgCache::DepIterator D = I.RevDependsList(); D.end() == false; D++)
+ {
+ // Only do it for the install version
+ if ((pkgCache::Version *)D.ParentVer() != Cache[D.ParentPkg()].InstallVer ||
+ (D->Type != pkgDEP_Depends && D->Type != pkgDEP_PreDepends))
+ continue;
+
+ Scores[I->ID] += abs(OldScores[D.ParentPkg()->ID]);
+ }
+ }
+
+ /* Now we propogate along provides. This makes the packages that
+ provide important packages extremely important */
+ for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+ {
+ for (pkgCache::PrvIterator P = I.ProvidesList(); P.end() == false; P++)
+ {
+ // Only do it once per package
+ if ((pkgCache::Version *)P.OwnerVer() != Cache[P.OwnerPkg()].InstallVer)
+ continue;
+ Scores[P.OwnerPkg()->ID] += abs(Scores[I->ID] - OldScores[I->ID]);
+ }
+ }
+
+ /* Protected things are pushed really high up. This number should put them
+ ahead of everything */
+ for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+ if ((Flags[I->ID] & Protected) != 0)
+ Scores[I->ID] += 10000;
+
+ delete [] OldScores;
+}
+ /*}}}*/
+// ProblemResolver::DoUpgrade - Attempt to upgrade this package /*{{{*/
+// ---------------------------------------------------------------------
+/* This goes through and tries to reinstall packages to make this package
+ installable */
+bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg)
+{
+ if ((Flags[Pkg->ID] & Upgradable) == 0 || Cache[Pkg].Upgradable() == false)
+ return false;
+ Flags[Pkg->ID] &= ~Upgradable;
+
+ bool WasKept = Cache[Pkg].Keep();
+ Cache.MarkInstall(Pkg,false);
+
+ // Isolate the problem dependency
+ bool Fail = false;
+ for (pkgCache::DepIterator D = Cache[Pkg].InstVerIter(Cache).DependsList(); D.end() == false;)
+ {
+ // Compute a single dependency element (glob or)
+ pkgCache::DepIterator Start = D;
+ pkgCache::DepIterator End = D;
+ unsigned char State = 0;
+ for (bool LastOR = true; D.end() == false && LastOR == true; D++)
+ {
+ State |= Cache[D];
+ LastOR = (D->CompareOp & pkgOP_OR) == pkgOP_OR;
+ if (LastOR == true)
+ End = D;
+ }
+
+ // We only worry about critical deps.
+ if (End.IsCritical() != true)
+ continue;
+
+ // Dep is ok
+ if ((Cache[End] & pkgDepCache::DepGInstall) == pkgDepCache::DepGInstall)
+ continue;
+
+ // Hm, the group is broken.. I have no idea how to handle this
+ if (Start != End)
+ {
+ cout << "Note, a broken or group was found in " << Pkg.Name() << "." << endl;
+ Fail = true;
+ break;
+ }
+
+ // Upgrade the package if the candidate version will fix the problem.
+ if ((Cache[Start] & pkgDepCache::DepCVer) == pkgDepCache::DepCVer)
+ {
+ PkgIterator P = Start.SmartTargetPkg();
+ if (DoUpgrade(P) == false)
+ {
+ if (Debug == true)
+ cout << " Reinst Failed because of " << P.Name() << endl;
+ Fail = true;
+ break;
+ }
+ }
+ else
+ {
+ /* We let the algorithm deal with conflicts on its next iteration,
+ it is much smarter than us */
+ if (End->Type == pkgDEP_Conflicts)
+ continue;
+
+ if (Debug == true)
+ cout << " Reinst Failed early because of " << Start.TargetPkg().Name() << endl;
+ Fail = true;
+ break;
+ }
+ }
+
+ // Undo our operations - it might be smart to undo everything this did..
+ if (Fail == true)
+ {
+ if (WasKept == true)
+ Cache.MarkKeep(Pkg);
+ else
+ Cache.MarkDelete(Pkg);
+ return false;
+ }
+
+ if (Debug == true)
+ cout << " Re-Instated " << Pkg.Name() << endl;
+ return true;
+}
+ /*}}}*/
+// ProblemResolver::Resolve - Run the resolution pass /*{{{*/
+// ---------------------------------------------------------------------
+/* This routines works by calculating a score for each package. The score
+ is derived by considering the package's priority and all reverse
+ dependents giving an integer that reflects the amount of breakage that
+ adjusting the package will inflict.
+
+ It goes from highest score to lowest and corrects all of the breaks by
+ keeping or removing the dependant packages. If that fails then it removes
+ the package itself and goes on. The routine should be able to intelligently
+ go from any broken state to a fixed state.
+
+ The BrokenFix flag enables a mode where the algorithm tries to
+ upgrade packages to advoid problems. */
+bool pkgProblemResolver::Resolve(bool BrokenFix)
+{
+ unsigned long Size = Cache.HeaderP->PackageCount;
+
+ // Record which packages are marked for install
+ bool Again = false;
+ do
+ {
+ Again = false;
+ for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+ {
+ if (Cache[I].Install() == true)
+ Flags[I->ID] |= PreInstalled;
+ else
+ {
+ if (Cache[I].InstBroken() == true && BrokenFix == true)
+ {
+ Cache.MarkInstall(I,false);
+ if (Cache[I].Install() == true)
+ Again = true;
+ }
+
+ Flags[I->ID] &= ~PreInstalled;
+ }
+ Flags[I->ID] |= Upgradable;
+ }
+ }
+ while (Again == true);
+
+ if (Debug == true)
+ cout << "Starting" << endl;
+
+ MakeScores();
+
+ /* We have to order the packages so that the broken fixing pass
+ operates from highest score to lowest. This prevents problems when
+ high score packages cause the removal of lower score packages that
+ would cause the removal of even lower score packages. */
+ pkgCache::Package **PList = new pkgCache::Package *[Size];
+ pkgCache::Package **PEnd = PList;
+ for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+ *PEnd++ = I;
+ This = this;
+ qsort(PList,PEnd - PList,sizeof(*PList),&ScoreSort);
+
+/* for (pkgCache::Package **K = PList; K != PEnd; K++)
+ if (Scores[(*K)->ID] != 0)
+ {
+ pkgCache::PkgIterator Pkg(Cache,*K);
+ cout << Scores[(*K)->ID] << ' ' << Pkg.Name() <<
+ ' ' << (pkgCache::Version *)Pkg.CurrentVer() << ' ' <<
+ Cache[Pkg].InstallVer << ' ' << Cache[Pkg].CandidateVer << endl;
+ } */
+
+ if (Debug == true)
+ cout << "Starting 2" << endl;
+
+ /* Now consider all broken packages. For each broken package we either
+ remove the package or fix it's problem. We do this once, it should
+ not be possible for a loop to form (that is a < b < c and fixing b by
+ changing a breaks c) */
+ bool Change = true;
+ for (int Counter = 0; Counter != 10 && Change == true; Counter++)
+ {
+ Change = false;
+ for (pkgCache::Package **K = PList; K != PEnd; K++)
+ {
+ pkgCache::PkgIterator I(Cache,*K);
+
+ /* We attempt to install this and see if any breaks result,
+ this takes care of some strange cases */
+ if (Cache[I].CandidateVer != Cache[I].InstallVer &&
+ I->CurrentVer != 0 && Cache[I].InstallVer != 0 &&
+ (Flags[I->ID] & PreInstalled) != 0 &&
+ (Flags[I->ID] & Protected) == 0)
+ {
+ if (Debug == true)
+ cout << " Try to Re-Instate " << I.Name() << endl;
+ int OldBreaks = Cache.BrokenCount();
+ pkgCache::Version *OldVer = Cache[I].InstallVer;
+
+ Cache.MarkInstall(I,false);
+ if (Cache[I].InstBroken() == true ||
+ OldBreaks < Cache.BrokenCount())
+ {
+ if (OldVer == 0)
+ Cache.MarkDelete(I);
+ else
+ Cache.MarkKeep(I);
+ }
+ else
+ if (Debug == true)
+ cout << "Re-Instated " << I.Name() << endl;
+ }
+
+ if (Cache[I].InstallVer == 0 || Cache[I].InstBroken() == false)
+ continue;
+
+ // Isolate the problem dependency
+ PackageKill KillList[100];
+ PackageKill *LEnd = KillList;
+ for (pkgCache::DepIterator D = Cache[I].InstVerIter(Cache).DependsList(); D.end() == false;)
+ {
+ // Compute a single dependency element (glob or)
+ pkgCache::DepIterator Start = D;
+ pkgCache::DepIterator End = D;
+ unsigned char State = 0;
+ for (bool LastOR = true; D.end() == false && LastOR == true; D++)
+ {
+ State |= Cache[D];
+ LastOR = (D->CompareOp & pkgOP_OR) == pkgOP_OR;
+ if (LastOR == true)
+ End = D;
+ }
+
+ // We only worry about critical deps.
+ if (End.IsCritical() != true)
+ continue;
+
+ // Dep is ok
+ if ((Cache[End] & pkgDepCache::DepGInstall) == pkgDepCache::DepGInstall)
+ continue;
+
+ // Hm, the group is broken.. I have no idea how to handle this
+ if (Start != End)
+ {
+ cout << "Note, a broken or group was found in " << I.Name() << "." << endl;
+ Cache.MarkDelete(I);
+ break;
+ }
+
+ if (Debug == true)
+ cout << "Package " << I.Name() << " has broken dep on " << End.TargetPkg().Name() << endl;
+
+ /* Conflicts is simple, decide if we should remove this package
+ or the conflicted one */
+ pkgCache::Version **VList = End.AllTargets();
+ bool Done = false;
+ for (pkgCache::Version **V = VList; *V != 0; V++)
+ {
+ pkgCache::VerIterator Ver(Cache,*V);
+ pkgCache::PkgIterator Pkg = Ver.ParentPkg();
+
+ if (Debug == true)
+ cout << " Considering " << Pkg.Name() << ' ' << (int)Scores[Pkg->ID] <<
+ " as a solution to " << I.Name() << ' ' << (int)Scores[I->ID] << endl;
+ if (Scores[I->ID] <= Scores[Pkg->ID] ||
+ ((Cache[End] & pkgDepCache::DepGNow) == 0 &&
+ End->Type != pkgDEP_Conflicts))
+ {
+ if ((Flags[I->ID] & Protected) != 0)
+ continue;
+
+ // See if a keep will do
+ Cache.MarkKeep(I);
+ if (Cache[I].InstBroken() == false)
+ {
+ if (Debug == true)
+ cout << " Holding Back " << I.Name() << " rather than change " << End.TargetPkg().Name() << endl;
+ }
+ else
+ {
+ if (BrokenFix == false || DoUpgrade(I) == false)
+ {
+ if (Debug == true)
+ cout << " Removing " << I.Name() << " rather than change " << End.TargetPkg().Name() << endl;
+ Cache.MarkDelete(I);
+ if (Counter > 1)
+ Scores[I->ID] = Scores[Pkg->ID];
+ }
+ }
+
+ Change = true;
+ Done = true;
+ break;
+ }
+ else
+ {
+ // Skip this if it is protected
+ if ((Flags[Pkg->ID] & Protected) != 0)
+ continue;
+
+ LEnd->Pkg = Pkg;
+ LEnd->Dep = End;
+ LEnd++;
+ if (End->Type != pkgDEP_Conflicts)
+ break;
+ }
+ }
+
+ // Hm, nothing can possibly satisify this dep. Nuke it.
+ if (VList[0] == 0 && End->Type != pkgDEP_Conflicts)
+ {
+ Cache.MarkKeep(I);
+ if (Cache[I].InstBroken() == false)
+ {
+ if (Debug == true)
+ cout << " Holding Back " << I.Name() << " because I can't find " << End.TargetPkg().Name() << endl;
+ }
+ else
+ {
+ if (Debug == true)
+ cout << " Removing " << I.Name() << " because I can't find " << End.TargetPkg().Name() << endl;
+ Cache.MarkDelete(I);
+ }
+
+ Change = true;
+ Done = true;
+ }
+
+ delete [] VList;
+ if (Done == true)
+ break;
+ }
+
+ // Apply the kill list now
+ if (Cache[I].InstallVer != 0)
+ for (PackageKill *J = KillList; J != LEnd; J++)
+ {
+ Change = true;
+ if ((Cache[J->Dep] & pkgDepCache::DepGNow) == 0)
+ {
+ if (J->Dep->Type == pkgDEP_Conflicts)
+ {
+ if (Debug == true)
+ cout << " Fixing " << I.Name() << " via remove of " << J->Pkg.Name() << endl;
+ Cache.MarkDelete(J->Pkg);
+ }
+ }
+ else
+ {
+ if (Debug == true)
+ cout << " Fixing " << I.Name() << " via keep of " << J->Pkg.Name() << endl;
+ Cache.MarkKeep(J->Pkg);
+ }
+
+ if (Counter > 1)
+ Scores[J->Pkg->ID] = Scores[I->ID];
+ }
+ }
+ }
+
+ if (Debug == true)
+ cout << "Done" << endl;
+
+ delete [] Scores;
+ delete [] PList;
+
+ if (Cache.BrokenCount() != 0)
+ return _error->Error("Internal error, ScoredFix generated breaks.");
+
+ return true;
+}
+ /*}}}*/
diff --git a/apt-pkg/algorithms.h b/apt-pkg/algorithms.h
new file mode 100644
index 000000000..0dd77d940
--- /dev/null
+++ b/apt-pkg/algorithms.h
@@ -0,0 +1,91 @@
+// -*- mode: cpp; mode: fold -*-
+// Description /*{{{*/
+// $Id: algorithms.h,v 1.1 1998/07/07 04:17:00 jgg Exp $
+/* ######################################################################
+
+ Algorithms - A set of misc algorithms
+
+ This simulate class displays what the ordering code has done and
+ analyses it with a fresh new dependency cache. In this way we can
+ see all of the effects of an upgrade run.
+
+ pkgDistUpgrade computes an upgrade that causes as many packages as
+ possible to move to the newest verison.
+
+ pkgApplyStatus sets the target state based on the content of the status
+ field in the status file. It is important to get proper crash recovery.
+
+ ##################################################################### */
+ /*}}}*/
+// Header section: pkglib
+#ifndef PKGLIB_ALGORITHMS_H
+#define PKGLIB_ALGORITHMS_H
+
+#ifdef __GNUG__
+#pragma interface "pkglib/algorithms.h"
+#endif
+
+#include <pkglib/packagemanager.h>
+#include <pkglib/depcache.h>
+
+class pkgSimulate : public pkgPackageManager
+{
+ protected:
+
+ unsigned char *Flags;
+
+ pkgDepCache Sim;
+
+ // The Actuall installation implementation
+ virtual bool Install(PkgIterator Pkg,string File);
+ virtual bool Configure(PkgIterator Pkg);
+ virtual bool Remove(PkgIterator Pkg);
+ void ShortBreaks();
+
+ public:
+
+ pkgSimulate(pkgDepCache &Cache);
+};
+
+class pkgProblemResolver
+{
+ pkgDepCache &Cache;
+ typedef pkgCache::PkgIterator PkgIterator;
+ typedef pkgCache::VerIterator VerIterator;
+ typedef pkgCache::DepIterator DepIterator;
+ typedef pkgCache::PrvIterator PrvIterator;
+ typedef pkgCache::Version Version;
+ typedef pkgCache::Package Package;
+
+ enum Flags {Protected = (1 << 0), PreInstalled = (1 << 1),
+ Upgradable = (1 << 2)};
+ signed short *Scores;
+ unsigned char *Flags;
+ bool Debug;
+
+ // Sort stuff
+ static pkgProblemResolver *This;
+ static int ScoreSort(const void *a,const void *b);
+
+ struct PackageKill
+ {
+ PkgIterator Pkg;
+ DepIterator Dep;
+ };
+
+ void MakeScores();
+ bool DoUpgrade(pkgCache::PkgIterator Pkg);
+
+ public:
+
+ inline void Protect(pkgCache::PkgIterator Pkg) {Flags[Pkg->ID] |= Protected;};
+ bool Resolve(bool BrokenFix = false);
+
+ pkgProblemResolver(pkgDepCache &Cache);
+};
+
+bool pkgDistUpgrade(pkgDepCache &Cache);
+bool pkgApplyStatus(pkgDepCache &Cache);
+bool pkgFixBroken(pkgDepCache &Cache);
+
+#endif
diff --git a/apt-pkg/cacheiterators.h b/apt-pkg/cacheiterators.h
index f12491fe1..f234526db 100644
--- a/apt-pkg/cacheiterators.h
+++ b/apt-pkg/cacheiterators.h
@@ -1,6 +1,6 @@
// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: cacheiterators.h,v 1.3 1998/07/05 05:33:52 jgg Exp $
+// $Id: cacheiterators.h,v 1.4 1998/07/07 04:17:00 jgg Exp $
/* ######################################################################
Cache Iterators - Iterators for navigating the cache structure
@@ -21,7 +21,8 @@
The DepIterator can iterate over two lists, a list of 'version depends'
or a list of 'package reverse depends'. The type is determined by the
structure passed to the constructor, which should be the structure
- that has the depends pointer as a member.
+ that has the depends pointer as a member. The provide iterator has the
+ same system.
This header is not user includable, please use pkglib/pkgcache.h
@@ -31,6 +32,10 @@
#ifndef PKGLIB_CACHEITERATORS_H
#define PKGLIB_CACHEITERATORS_H
+#ifdef __GNUG__
+#pragma interface "pkglib/cacheiterators.h"
+#endif
+
// Package Iterator
class pkgCache::PkgIterator
{
@@ -57,6 +62,7 @@ class pkgCache::PkgIterator
inline Package const &operator *() const {return *Pkg;};
inline operator Package *() {return Pkg == Owner->PkgP?0:Pkg;};
inline operator Package const *() const {return Pkg == Owner->PkgP?0:Pkg;};
+
inline const char *Name() const {return Pkg->Name == 0?0:Owner->StrP + Pkg->Name;};
inline const char *Section() const {return Pkg->Section == 0?0:Owner->StrP + Pkg->Section;};
inline const char *TargetDist() const {return Pkg->TargetDist == 0?0:Owner->StrP + Pkg->TargetDist;};
@@ -111,13 +117,14 @@ class pkgCache::VerIterator
inline Version const &operator *() const {return *Ver;};
inline operator Version *() {return Ver == Owner.VerP?0:Ver;};
inline operator Version const *() const {return Ver == Owner.VerP?0:Ver;};
+
inline const char *VerStr() const {return Ver->VerStr == 0?0:Owner.StrP + Ver->VerStr;};
inline const char *Section() const {return Ver->Section == 0?0:Owner.StrP + Ver->Section;};
inline PkgIterator ParentPkg() const {return PkgIterator(Owner,Owner.PkgP + Ver->ParentPkg);};
inline DepIterator DependsList() const;
inline PrvIterator ProvidesList() const;
- inline unsigned long Index() const {return Ver - Owner.VerP;};
inline VerFileIterator FileList() const;
+ inline unsigned long Index() const {return Ver - Owner.VerP;};
inline VerIterator(pkgCache &Owner,Version *Trg = 0) : Ver(Trg), Owner(Owner)
{
@@ -154,16 +161,17 @@ class pkgCache::DepIterator
inline Dependency const &operator *() const {return *Dep;};
inline operator Dependency *() {return Dep == Owner->DepP?0:Dep;};
inline operator Dependency const *() const {return Dep == Owner->DepP?0:Dep;};
+
inline const char *TargetVer() const {return Dep->Version == 0?0:Owner->StrP + Dep->Version;};
inline PkgIterator TargetPkg() {return PkgIterator(*Owner,Owner->PkgP + Dep->Package);};
- Version **AllTargets();
- bool SmartTargetPkg(PkgIterator &Result);
inline PkgIterator SmartTargetPkg() {PkgIterator R(*Owner);SmartTargetPkg(R);return R;};
inline VerIterator ParentVer() {return VerIterator(*Owner,Owner->VerP + Dep->ParentVer);};
inline PkgIterator ParentPkg() {return PkgIterator(*Owner,Owner->PkgP + Owner->VerP[Dep->ParentVer].ParentPkg);};
- bool IsCritical();
inline bool Reverse() {return Type == DepRev;};
inline unsigned long Index() const {return Dep - Owner->DepP;};
+ bool IsCritical();
+ Version **AllTargets();
+ bool SmartTargetPkg(PkgIterator &Result);
inline DepIterator(pkgCache &Owner,Dependency *Trg,Version * = 0) :
Dep(Trg), Type(DepVer), Owner(&Owner)
@@ -208,6 +216,7 @@ class pkgCache::PrvIterator
inline Provides const &operator *() const {return *Prv;};
inline operator Provides *() {return Prv == Owner->ProvideP?0:Prv;};
inline operator Provides const *() const {return Prv == Owner->ProvideP?0:Prv;};
+
inline const char *Name() const {return Owner->StrP + Owner->PkgP[Prv->ParentPkg].Name;};
inline const char *ProvideVersion() const {return Prv->ProvideVersion == 0?0:Owner->StrP + Prv->ProvideVersion;};
inline PkgIterator ParentPkg() {return PkgIterator(*Owner,Owner->PkgP + Prv->ParentPkg);};
diff --git a/apt-pkg/contrib/configuration.cc b/apt-pkg/contrib/configuration.cc
new file mode 100644
index 000000000..6d937d657
--- /dev/null
+++ b/apt-pkg/contrib/configuration.cc
@@ -0,0 +1,137 @@
+// -*- mode: cpp; mode: fold -*-
+// Description /*{{{*/
+// $Id: configuration.cc,v 1.1 1998/07/07 04:17:10 jgg Exp $
+/* ######################################################################
+
+ Configuration Class
+
+ This class provides a configuration file and command line parser
+ for a tree-oriented configuration environment. All runtime configuration
+ is stored in here.
+
+ ##################################################################### */
+ /*}}}*/
+// Include files /*{{{*/
+#ifdef __GNUG__
+#pragma implementation "pkglib/configuration.h"
+#endif
+#include <pkglib/configuration.h>
+#include <strutl.h>
+
+#include <stdio.h>
+ /*}}}*/
+Configuration *_config;
+
+// Configuration::Configuration - Constructor /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+Configuration::Configuration()
+{
+ Root = new Item;
+}
+ /*}}}*/
+// Configuration::Lookup - Lookup a single item /*{{{*/
+// ---------------------------------------------------------------------
+/* This will lookup a single item by name below another item. It is a
+ helper function for the main lookup function */
+Configuration::Item *Configuration::Lookup(Item *Head,const char *S,
+ unsigned long Len,bool Create)
+{
+ int Res = 1;
+ Item *I = Head->Child;
+ Item **Last = &Head->Child;
+ for (; I != 0; Last = &I->Next, I = I->Next)
+ if ((Res = stringcasecmp(I->Value.begin(),I->Value.end(),S,S + Len)) == 0)
+ break;
+
+ if (Res == 0)
+ return I;
+ if (Create == false)
+ return 0;
+
+ I = new Item;
+ I->Value = string(S,Len);
+ I->Next = *Last;
+ *Last = I;
+ return I;
+}
+ /*}}}*/
+// Configuration::Lookup - Lookup a fully scoped item /*{{{*/
+// ---------------------------------------------------------------------
+/* This performs a fully scoped lookup of a given name, possibly creating
+ new items */
+Configuration::Item *Configuration::Lookup(const char *Name,bool Create)
+{
+ const char *Start = Name;
+ const char *End = Start + strlen(Name);
+ const char *TagEnd = Name;
+ Item *Itm = Root;
+ for (; End - TagEnd > 2; TagEnd++)
+ {
+ if (TagEnd[0] == ':' && TagEnd[1] == ':')
+ {
+ Itm = Lookup(Itm,Start,TagEnd - Start,Create);
+ if (Itm == 0)
+ return 0;
+ TagEnd = Start = TagEnd + 2;
+ }
+ }
+
+ Itm = Lookup(Itm,Start,End - Start,Create);
+ if (Itm == 0)
+ return 0;
+ return Itm;
+}
+ /*}}}*/
+// Configuration::Find - Find a value /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+string Configuration::Find(const char *Name,const char *Default)
+{
+ Item *Itm = Lookup(Name,false);
+ if (Itm == 0 || Itm->Value.empty() == true)
+ return Default;
+ return Itm->Value;
+}
+ /*}}}*/
+// Configuration::FindI - Find an integer value /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+int Configuration::FindI(const char *Name,int Default)
+{
+ Item *Itm = Lookup(Name,false);
+ if (Itm == 0 || Itm->Value.empty() == true)
+ return Default;
+
+ char *End;
+ int Res = strtol(Itm->Value.c_str(),&End,0);
+ if (End == Itm->Value.c_str())
+ return Default;
+
+ return Res;
+}
+ /*}}}*/
+// Configuration::Set - Set a value /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+void Configuration::Set(const char *Name,string Value)
+{
+ Item *Itm = Lookup(Name,true);
+ if (Itm == 0)
+ return;
+ Itm->Value = Value;
+}
+ /*}}}*/
+// Configuration::Set - Set an integer value /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+void Configuration::Set(const char *Name,int Value)
+{
+ Item *Itm = Lookup(Name,true);
+ if (Itm == 0)
+ return;
+ char S[300];
+ snprintf(S,sizeof(S),"%i",Value);
+ Itm->Value = S;
+}
+ /*}}}*/
diff --git a/apt-pkg/contrib/configuration.h b/apt-pkg/contrib/configuration.h
new file mode 100644
index 000000000..7476346ef
--- /dev/null
+++ b/apt-pkg/contrib/configuration.h
@@ -0,0 +1,61 @@
+// -*- mode: cpp; mode: fold -*-
+// Description /*{{{*/
+// $Id: configuration.h,v 1.1 1998/07/07 04:17:10 jgg Exp $
+/* ######################################################################
+
+ Configuration Class
+
+ This class provides a configuration file and command line parser
+ for a tree-oriented configuration environment. All runtime configuration
+ is stored in here.
+
+ Each configuration name is given as a fully scoped string such as
+ Foo::Bar
+ And has associated with it a text string. The Configuration class only
+ provides storage and lookup for this tree, other classes provide
+ configuration file formats (and parsers/emitters if needed).
+
+ Most things can get by quite happily with,
+ cout << _config->Find("Foo::Bar") << endl;
+
+ ##################################################################### */
+ /*}}}*/
+// Header section: pkglib
+#ifndef PKGLIB_TAGFILE_H
+#define PKGLIB_TAGFILE_H
+
+#ifdef __GNUG__
+#pragma interface "pkglib/configuration.h"
+#endif
+
+#include <string>
+
+class Configuration
+{
+ struct Item
+ {
+ string Value;
+ string Tag;
+ Item *Child;
+ Item *Next;
+ Item() : Child(0), Next(0) {};
+ };
+ Item *Root;
+
+ Item *Lookup(Item *Head,const char *S,unsigned long Len,bool Create);
+ Item *Lookup(const char *Name,bool Create);
+
+ public:
+
+ string Find(const char *Name,const char *Default = 0);
+ int FindI(const char *Name,int Default = 0);
+
+ void Set(const char *Name,string Value);
+ void Set(const char *Name,int Value);
+
+ Configuration();
+};
+
+extern Configuration *_config;
+
+#endif
diff --git a/apt-pkg/contrib/error.cc b/apt-pkg/contrib/error.cc
index 59d2b8c8b..d1ea1b87b 100644
--- a/apt-pkg/contrib/error.cc
+++ b/apt-pkg/contrib/error.cc
@@ -1,6 +1,6 @@
// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: error.cc,v 1.1 1998/07/02 02:58:13 jgg Exp $
+// $Id: error.cc,v 1.2 1998/07/07 04:17:10 jgg Exp $
/* ######################################################################
Global Erorr Class - Global error mechanism
@@ -14,6 +14,10 @@
##################################################################### */
/*}}}*/
// Include Files /*{{{*/
+#ifdef __GNUG__
+#pragma implementation "pkglib/error.h"
+#endif
+
#include <errno.h>
#include <stdio.h>
#include <string.h>
@@ -27,7 +31,7 @@ GlobalError *_error = new GlobalError;
// GlobalError::GlobalError - Constructor /*{{{*/
// ---------------------------------------------------------------------
/* */
-GlobalError::GlobalError() : PendingFlag(false)
+GlobalError::GlobalError() : List(0), PendingFlag(false)
{
}
/*}}}*/
@@ -49,10 +53,10 @@ bool GlobalError::Errno(const char *Function,const char *Description,...)
sprintf(S + strlen(S)," - %s (%i %s)",Function,errno,strerror(errno));
// Put it on the list
- Item Itm;
- Itm.Text = S;
- Itm.Error = true;
- List.push_back(Itm);
+ Item *Itm = new Item;
+ Itm->Text = S;
+ Itm->Error = true;
+ Insert(Itm);
PendingFlag = true;
@@ -72,10 +76,10 @@ bool GlobalError::Error(const char *Description,...)
vsprintf(S,Description,args);
// Put it on the list
- Item Itm;
- Itm.Text = S;
- Itm.Error = true;
- List.push_back(Itm);
+ Item *Itm = new Item;
+ Itm->Text = S;
+ Itm->Error = true;
+ Insert(Itm);
PendingFlag = true;
@@ -95,10 +99,10 @@ bool GlobalError::Warning(const char *Description,...)
vsprintf(S,Description,args);
// Put it on the list
- Item Itm;
- Itm.Text = S;
- Itm.Error = false;
- List.push_back(Itm);
+ Item *Itm = new Item;
+ Itm->Text = S;
+ Itm->Error = false;
+ Insert(Itm);
return false;
}
@@ -109,12 +113,17 @@ bool GlobalError::Warning(const char *Description,...)
true if the message is an error. */
bool GlobalError::PopMessage(string &Text)
{
- bool Ret = List.front().Error;
- Text = List.front().Text;
- List.erase(List.begin());
-
+ if (List == 0)
+ return false;
+
+ bool Ret = List->Error;
+ Text = List->Text;
+ Item *Old = List;
+ List = List->Next;
+ delete Old;
+
// This really should check the list to see if only warnings are left..
- if (empty())
+ if (List == 0)
PendingFlag = false;
return Ret;
@@ -137,3 +146,30 @@ void GlobalError::DumpErrors()
}
}
/*}}}*/
+// GlobalError::Discard - Discard /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+void GlobalError::Discard()
+{
+ while (List != 0)
+ {
+ Item *Old = List;
+ List = List->Next;
+ delete Old;
+ }
+
+ PendingFlag = false;
+};
+ /*}}}*/
+// GlobalError::Insert - Insert a new item at the end /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+void GlobalError::Insert(Item *Itm)
+{
+ Item **End = &List;
+ for (Item *I = List; I != 0; I = I->Next)
+ End = &I->Next;
+ Itm->Next = *End;
+ *End = Itm;
+}
+ /*}}}*/
diff --git a/apt-pkg/contrib/error.h b/apt-pkg/contrib/error.h
index 06b998e5e..06367592b 100644
--- a/apt-pkg/contrib/error.h
+++ b/apt-pkg/contrib/error.h
@@ -1,6 +1,6 @@
// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: error.h,v 1.1 1998/07/02 02:58:13 jgg Exp $
+// $Id: error.h,v 1.2 1998/07/07 04:17:11 jgg Exp $
/* ######################################################################
Global Erorr Class - Global error mechanism
@@ -41,8 +41,11 @@
#ifndef PKGLIB_ERROR_H
#define PKGLIB_ERROR_H
+#ifdef __GNUG__
+#pragma interface "pkglib/error.h"
+#endif
+
#include <string>
-#include <vector.h>
class GlobalError
{
@@ -50,10 +53,12 @@ class GlobalError
{
string Text;
bool Error;
+ Item *Next;
};
- vector<Item> List;
+ Item *List;
bool PendingFlag;
+ void Insert(Item *I);
public:
@@ -67,9 +72,9 @@ class GlobalError
// Simple accessors
inline bool PendingError() {return PendingFlag;};
- inline bool empty() {return List.empty();};
+ inline bool empty() {return List == 0;};
bool PopMessage(string &Text);
- void Discard() {List.erase(List.begin(),List.end()); PendingFlag = false;};
+ void Discard();
// Usefull routine to dump to cerr
void DumpErrors();
diff --git a/apt-pkg/contrib/fileutl.cc b/apt-pkg/contrib/fileutl.cc
index 6c6441ef6..29b12bef1 100644
--- a/apt-pkg/contrib/fileutl.cc
+++ b/apt-pkg/contrib/fileutl.cc
@@ -1,6 +1,6 @@
// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: fileutl.cc,v 1.2 1998/07/04 05:57:41 jgg Exp $
+// $Id: fileutl.cc,v 1.3 1998/07/07 04:17:12 jgg Exp $
/* ######################################################################
File Utilities
@@ -14,6 +14,9 @@
##################################################################### */
/*}}}*/
// Include Files /*{{{*/
+#ifdef __GNUG__
+#pragma implementation "pkglib/fileutl.h"
+#endif
#include <pkglib/fileutl.h>
#include <pkglib/error.h>
diff --git a/apt-pkg/contrib/fileutl.h b/apt-pkg/contrib/fileutl.h
index 1b6666843..aa2d2ee2e 100644
--- a/apt-pkg/contrib/fileutl.h
+++ b/apt-pkg/contrib/fileutl.h
@@ -1,6 +1,6 @@
// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: fileutl.h,v 1.1 1998/07/02 02:58:13 jgg Exp $
+// $Id: fileutl.h,v 1.2 1998/07/07 04:17:13 jgg Exp $
/* ######################################################################
File Utilities
@@ -22,6 +22,10 @@
#ifndef PKGLIB_FILEUTL_H
#define PKGLIB_FILEUTL_H
+#ifdef __GNUG__
+#pragma interface "pkglib/fileutl.h"
+#endif
+
#include <string>
class File
diff --git a/apt-pkg/contrib/mmap.cc b/apt-pkg/contrib/mmap.cc
index 41ea02aec..c0cc13f00 100644
--- a/apt-pkg/contrib/mmap.cc
+++ b/apt-pkg/contrib/mmap.cc
@@ -1,6 +1,6 @@
// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: mmap.cc,v 1.3 1998/07/04 22:32:15 jgg Exp $
+// $Id: mmap.cc,v 1.4 1998/07/07 04:17:14 jgg Exp $
/* ######################################################################
MMap Class - Provides 'real' mmap or a faked mmap using read().
@@ -21,6 +21,10 @@
##################################################################### */
/*}}}*/
// Include Files /*{{{*/
+#ifdef __GNUG__
+#pragma implementation "pkglib/mmap.h"
+#endif
+
#define _BSD_SOURCE
#include <pkglib/mmap.h>
#include <pkglib/error.h>
diff --git a/apt-pkg/contrib/mmap.h b/apt-pkg/contrib/mmap.h
index c7ddf685d..55feda741 100644
--- a/apt-pkg/contrib/mmap.h
+++ b/apt-pkg/contrib/mmap.h
@@ -1,6 +1,6 @@
// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: mmap.h,v 1.2 1998/07/04 05:57:43 jgg Exp $
+// $Id: mmap.h,v 1.3 1998/07/07 04:17:15 jgg Exp $
/* ######################################################################
MMap Class - Provides 'real' mmap or a faked mmap using read().
@@ -26,6 +26,10 @@
#ifndef PKGLIB_MMAP_H
#define PKGLIB_MMAP_H
+#ifdef __GNUG__
+#pragma interface "pkglib/mmap.h"
+#endif
+
#include <string>
#include <pkglib/fileutl.h>
diff --git a/apt-pkg/contrib/strutl.cc b/apt-pkg/contrib/strutl.cc
new file mode 100644
index 000000000..14965f91e
--- /dev/null
+++ b/apt-pkg/contrib/strutl.cc
@@ -0,0 +1,343 @@
+// -*- mode: cpp; mode: fold -*-
+// Description /*{{{*/
+// $Id: strutl.cc,v 1.1 1998/07/07 04:17:16 jgg Exp $
+/* ######################################################################
+
+ String Util - Some usefull string functions.
+
+ strstrip - Remove whitespace from the front and end of a line.
+
+ This source is placed in the Public Domain, do with it what you will
+ It was originally written by Jason Gunthorpe <jgg@gpu.srv.ualberta.ca>
+
+ ##################################################################### */
+ /*}}}*/
+// Includes /*{{{*/
+#include <strutl.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdio.h>
+ /*}}}*/
+
+// strstrip - Remove white space from the front and back of a string /*{{{*/
+// ---------------------------------------------------------------------
+/* This is handy to use when parsing a file. It also removes \n's left
+ over from fgets and company */
+char *_strstrip(char *String)
+{
+ for (;*String != 0 && (*String == ' ' || *String == '\t'); String++);
+
+ if (*String == 0)
+ return String;
+
+ char *End = String + strlen(String) - 1;
+ for (;End != String - 1 && (*End == ' ' || *End == '\t' || *End == '\n' ||
+ *End == '\r'); End--);
+ End++;
+ *End = 0;
+ return String;
+};
+ /*}}}*/
+// strtabexpand - Converts tabs into 8 spaces /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+char *_strtabexpand(char *String,size_t Len)
+{
+ for (char *I = String; I != I + Len && *I != 0; I++)
+ {
+ if (*I != '\t')
+ continue;
+ if (I + 8 > String + Len)
+ {
+ *I = 0;
+ return String;
+ }
+
+ /* Assume the start of the string is 0 and find the next 8 char
+ division */
+ int Len;
+ if (String == I)
+ Len = 1;
+ else
+ Len = 8 - ((String - I) % 8);
+ Len -= 2;
+ if (Len <= 0)
+ {
+ *I = ' ';
+ continue;
+ }
+
+ memmove(I + Len,I + 1,strlen(I) + 1);
+ for (char *J = I; J + Len != I; *I = ' ', I++);
+ }
+ return String;
+}
+ /*}}}*/
+// ParseQuoteWord - Parse a single word out of a string /*{{{*/
+// ---------------------------------------------------------------------
+/* This grabs a single word, converts any % escaped characters to their
+ proper values and advances the pointer. Double quotes are understood
+ and striped out as well. */
+bool ParseQuoteWord(const char *&String,string &Res)
+{
+ // Skip leading whitespace
+ const char *C = String;
+ for (;*C != 0 && *C == ' '; C++);
+ if (*C == 0)
+ return false;
+
+ // Jump to the next word
+ for (;*C != 0 && *C != ' '; C++)
+ {
+ if (*C == '"')
+ {
+ for (C++;*C != 0 && *C != '"'; C++);
+ if (*C == 0)
+ return false;
+ }
+ }
+
+ // Now de-quote characters
+ char Buffer[1024];
+ char Tmp[3];
+ const char *Start = String;
+ char *I;
+ for (I = Buffer; I < Buffer + sizeof(Buffer) && Start != C; I++)
+ {
+ if (*Start == '%' && Start + 2 < C)
+ {
+ Tmp[0] = Start[1];
+ Tmp[1] = Start[2];
+ Tmp[3] = 0;
+ *I = (char)strtol(Tmp,0,16);
+ Start += 3;
+ continue;
+ }
+ if (*Start != '"')
+ *I = *Start;
+ else
+ I--;
+ Start++;
+ }
+ *I = 0;
+ Res = Buffer;
+
+ // Skip ending white space
+ for (;*C != 0 && *C == ' '; C++);
+ String = C;
+ return true;
+}
+ /*}}}*/
+// QuoteString - Convert a string into quoted from /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+string QuoteString(string Str,const char *Bad)
+{
+ string Res;
+ for (string::iterator I = Str.begin(); I != Str.end(); I++)
+ {
+ if (strchr(Bad,*I) != 0 || isprint(*I) == 0 ||
+ *I <= 0x20 || *I >= 0x7F)
+ {
+ char Buf[10];
+ sprintf(Buf,"%%%02x",(int)*I);
+ Res += Buf;
+ }
+ else
+ Res += *I;
+ }
+ return Res;
+}
+ /*}}}*/
+// SizeToStr - Convert a long into a human readable size /*{{{*/
+// ---------------------------------------------------------------------
+/* A max of 4 digits are shown before conversion to the next highest unit. The
+ max length of the string will be 5 chars unless the size is > 10
+ YottaBytes (E24) */
+string SizeToStr(double Size)
+{
+ char S[300];
+ double ASize;
+ if (Size >= 0)
+ ASize = Size;
+ else
+ ASize = -1*Size;
+
+ /* bytes, KiloBytes, MegaBytes, GigaBytes, TeraBytes, PetaBytes,
+ ExaBytes, ZettaBytes, YottaBytes */
+ char Ext[] = {'b','k','M','G','T','P','E','Z','Y'};
+ int I = 0;
+ while (I <= 8)
+ {
+ if (ASize < 100 && I != 0)
+ {
+ sprintf(S,"%.1f%c",ASize,Ext[I]);
+ break;
+ }
+
+ if (ASize < 10000)
+ {
+ sprintf(S,"%.0f%c",ASize,Ext[I]);
+ break;
+ }
+ ASize /= 1000.0;
+ I++;
+ }
+
+ return S;
+}
+ /*}}}*/
+// TimeToStr - Convert the time into a string /*{{{*/
+// ---------------------------------------------------------------------
+/* Converts a number of seconds to a hms format */
+string TimeToStr(unsigned long Sec)
+{
+ char S[300];
+
+ while (1)
+ {
+ if (Sec > 60*60*24)
+ {
+ sprintf(S,"%lid %lih%lim%lis",Sec/60/60/24,(Sec/60/60) % 24,(Sec/60) % 60,Sec % 60);
+ break;
+ }
+
+ if (Sec > 60*60)
+ {
+ sprintf(S,"%lih%lim%lis",Sec/60/60,(Sec/60) % 60,Sec % 60);
+ break;
+ }
+
+ if (Sec > 60)
+ {
+ sprintf(S,"%lim%lis",Sec/60,Sec % 60);
+ break;
+ }
+
+ sprintf(S,"%lis",Sec);
+ break;
+ }
+
+ return S;
+}
+ /*}}}*/
+// SubstVar - Substitute a string for another string /*{{{*/
+// ---------------------------------------------------------------------
+/* This replaces all occurances of Subst with Contents in Str. */
+string SubstVar(string Str,string Subst,string Contents)
+{
+ string::size_type Pos;
+ string::size_type OldPos = 0;
+ string Temp;
+
+ while (OldPos < Str.length() &&
+ (Pos = Str.find(Subst,OldPos)) != string::npos)
+ {
+ Temp += string(Str,OldPos,Pos) + Contents;
+ OldPos = Pos + Subst.length();
+ }
+
+ if (OldPos == 0)
+ return Str;
+
+ return Temp + string(Str,OldPos);
+}
+ /*}}}*/
+// Base64Encode - Base64 Encoding routine for short strings /*{{{*/
+// ---------------------------------------------------------------------
+/* This routine performs a base64 transformation on a string. It was ripped
+ from wget and then patched and bug fixed.
+
+ This spec can be found in rfc2045 */
+string Base64Encode(string S)
+{
+ // Conversion table.
+ static char tbl[64] = {'A','B','C','D','E','F','G','H',
+ 'I','J','K','L','M','N','O','P',
+ 'Q','R','S','T','U','V','W','X',
+ 'Y','Z','a','b','c','d','e','f',
+ 'g','h','i','j','k','l','m','n',
+ 'o','p','q','r','s','t','u','v',
+ 'w','x','y','z','0','1','2','3',
+ '4','5','6','7','8','9','+','/'};
+
+ // Pre-allocate some space
+ string Final;
+ Final.reserve((4*S.length() + 2)/3 + 2);
+
+ /* Transform the 3x8 bits to 4x6 bits, as required by
+ base64. */
+ for (string::const_iterator I = S.begin(); I < S.end(); I += 3)
+ {
+ char Bits[3] = {0,0,0};
+ Bits[0] = I[0];
+ if (I + 1 < S.end())
+ Bits[1] = I[1];
+ if (I + 2 < S.end())
+ Bits[2] = I[2];
+
+ Final += tbl[Bits[0] >> 2];
+ Final += tbl[((Bits[0] & 3) << 4) + (Bits[1] >> 4)];
+
+ if (I + 1 >= S.end())
+ break;
+
+ Final += tbl[((Bits[1] & 0xf) << 2) + (Bits[2] >> 6)];
+
+ if (I + 2 >= S.end())
+ break;
+
+ Final += tbl[Bits[2] & 0x3f];
+ }
+
+ /* Apply the padding elements, this tells how many bytes the remote
+ end should discard */
+ if (S.length() % 3 == 2)
+ Final += '=';
+ if (S.length() % 3 == 1)
+ Final += "==";
+
+ return Final;
+}
+ /*}}}*/
+// stringcmp - Arbitary string compare /*{{{*/
+// ---------------------------------------------------------------------
+/* This safely compares two non-null terminated strings of arbitary
+ length */
+int stringcmp(const char *A,const char *AEnd,const char *B,const char *BEnd)
+{
+ for (; A != AEnd && B != BEnd; A++, B++)
+ if (*A != *B)
+ break;
+
+ if (A == AEnd && B == BEnd)
+ return 0;
+ if (A == AEnd)
+ return 1;
+ if (B == BEnd)
+ return -1;
+ if (*A < *B)
+ return -1;
+ return 1;
+}
+ /*}}}*/
+// stringcasecmp - Arbitary case insensitive string compare /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+int stringcasecmp(const char *A,const char *AEnd,const char *B,const char *BEnd)
+{
+ for (; A != AEnd && B != BEnd; A++, B++)
+ if (toupper(*A) != toupper(*B))
+ break;
+
+ if (A == AEnd && B == BEnd)
+ return 0;
+ if (A == AEnd)
+ return 1;
+ if (B == BEnd)
+ return -1;
+ if (toupper(*A) < toupper(*B))
+ return -1;
+ return 1;
+}
+ /*}}}*/
diff --git a/apt-pkg/contrib/strutl.h b/apt-pkg/contrib/strutl.h
new file mode 100644
index 000000000..44a10c2f3
--- /dev/null
+++ b/apt-pkg/contrib/strutl.h
@@ -0,0 +1,36 @@
+// -*- mode: cpp; mode: fold -*-
+// Description /*{{{*/
+// $Id: strutl.h,v 1.1 1998/07/07 04:17:16 jgg Exp $
+/* ######################################################################
+
+ String Util - These are some usefull string functions
+
+ _strstrip is a function to remove whitespace from the front and end
+ of a string.
+
+ This source is placed in the Public Domain, do with it what you will
+ It was originally written by Jason Gunthorpe <jgg@gpu.srv.ualberta.ca>
+
+ ##################################################################### */
+ /*}}}*/
+// This is a private header
+// Header section: /
+#ifndef STRUTL_H
+#define STRUTL_H
+
+#include <stdlib.h>
+#include <string>
+
+char *_strstrip(char *String);
+char *_strtabexpand(char *String,size_t Len);
+bool ParseQuoteWord(const char *&String,string &Res);
+string QuoteString(string Str,const char *Bad);
+string SizeToStr(double Bytes);
+string TimeToStr(unsigned long Sec);
+string SubstVar(string Str,string Subst,string Contents);
+string Base64Encode(string Str);
+
+int stringcmp(const char *A,const char *AEnd,const char *B,const char *BEnd);
+int stringcasecmp(const char *A,const char *AEnd,const char *B,const char *BEnd);
+
+#endif
diff --git a/apt-pkg/deb/deblistparser.cc b/apt-pkg/deb/deblistparser.cc
index 4c37eb775..5fbb43a9f 100644
--- a/apt-pkg/deb/deblistparser.cc
+++ b/apt-pkg/deb/deblistparser.cc
@@ -1,6 +1,6 @@
// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: deblistparser.cc,v 1.3 1998/07/05 05:34:00 jgg Exp $
+// $Id: deblistparser.cc,v 1.4 1998/07/07 04:17:16 jgg Exp $
/* ######################################################################
Package Cache Generator - Generator for the cache structure.
@@ -147,27 +147,27 @@ bool debListParser::NewVersion(pkgCache::VerIterator Ver)
const char *Stop;
if (Section.Find("Priority",Start,Stop) == true)
{
- WordList PrioList[] = {{"important",pkgCache::Important},
- {"required",pkgCache::Required},
- {"standard",pkgCache::Standard},
- {"optional",pkgCache::Optional},
- {"extra",pkgCache::Extra}};
+ WordList PrioList[] = {{"important",pkgCache::State::Important},
+ {"required",pkgCache::State::Required},
+ {"standard",pkgCache::State::Standard},
+ {"optional",pkgCache::State::Optional},
+ {"extra",pkgCache::State::Extra}};
if (GrabWord(string(Start,Stop-Start),PrioList,
_count(PrioList),Ver->Priority) == false)
return _error->Error("Malformed Priority line");
}
- if (ParseDepends(Ver,"Depends",pkgCache::Depends) == false)
+ if (ParseDepends(Ver,"Depends",pkgCache::Dep::Depends) == false)
return false;
- if (ParseDepends(Ver,"PreDepends",pkgCache::PreDepends) == false)
+ if (ParseDepends(Ver,"PreDepends",pkgCache::Dep::PreDepends) == false)
return false;
- if (ParseDepends(Ver,"Suggests",pkgCache::Suggests) == false)
+ if (ParseDepends(Ver,"Suggests",pkgCache::Dep::Suggests) == false)
return false;
- if (ParseDepends(Ver,"Recommends",pkgCache::Recommends) == false)
+ if (ParseDepends(Ver,"Recommends",pkgCache::Dep::Recommends) == false)
return false;
- if (ParseDepends(Ver,"Conflicts",pkgCache::Conflicts) == false)
+ if (ParseDepends(Ver,"Conflicts",pkgCache::Dep::Conflicts) == false)
return false;
- if (ParseDepends(Ver,"Replaces",pkgCache::Depends) == false)
+ if (ParseDepends(Ver,"Replaces",pkgCache::Dep::Depends) == false)
return false;
if (ParseProvides(Ver) == false)
@@ -186,9 +186,9 @@ bool debListParser::UsePackage(pkgCache::PkgIterator Pkg,
if (Pkg->Section == 0)
if ((Pkg->Section = UniqFindTagWrite("Section")) == 0)
return false;
- if (HandleFlag("Essential",Pkg->Flags,pkgCache::Essential) == false)
+ if (HandleFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false)
return false;
- if (HandleFlag("Immediate-Configure",Pkg->Flags,pkgCache::ImmediateConf) == false)
+ if (HandleFlag("Immediate-Configure",Pkg->Flags,pkgCache::Flag::ImmediateConf) == false)
return false;
if (ParseStatus(Pkg,Ver) == false)
return false;
@@ -223,11 +223,11 @@ bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg,
return _error->Error("Malformed Status line");
// Process the want field
- WordList WantList[] = {{"unknown",pkgCache::Unknown},
- {"install",pkgCache::Install},
- {"hold",pkgCache::Hold},
- {"deinstall",pkgCache::DeInstall},
- {"purge",pkgCache::Purge}};
+ WordList WantList[] = {{"unknown",pkgCache::State::Unknown},
+ {"install",pkgCache::State::Install},
+ {"hold",pkgCache::State::Hold},
+ {"deinstall",pkgCache::State::DeInstall},
+ {"purge",pkgCache::State::Purge}};
if (GrabWord(string(Start,I-Start),WantList,
_count(WantList),Pkg->SelectedState) == false)
return _error->Error("Malformed 1st word in the Status line");
@@ -240,10 +240,10 @@ bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg,
return _error->Error("Malformed status line, no 2nd word");
// Process the flag field
- WordList FlagList[] = {{"ok",pkgCache::Ok},
- {"reinstreq",pkgCache::ReInstReq},
- {"hold",pkgCache::HoldInst},
- {"hold-reinstreq",pkgCache::HoldReInstReq}};
+ WordList FlagList[] = {{"ok",pkgCache::State::Ok},
+ {"reinstreq",pkgCache::State::ReInstReq},
+ {"hold",pkgCache::State::HoldInst},
+ {"hold-reinstreq",pkgCache::State::HoldReInstReq}};
if (GrabWord(string(Start,I-Start),FlagList,
_count(FlagList),Pkg->InstState) == false)
return _error->Error("Malformed 2nd word in the Status line");
@@ -256,15 +256,15 @@ bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg,
return _error->Error("Malformed Status line, no 3rd word");
// Process the flag field
- WordList StatusList[] = {{"not-installed",pkgCache::NotInstalled},
- {"unpacked",pkgCache::UnPacked},
- {"half-configured",pkgCache::HalfConfigured},
- {"installed",pkgCache::Installed},
- {"uninstalled",pkgCache::UnInstalled},
- {"half-installed",pkgCache::HalfInstalled},
- {"config-files",pkgCache::ConfigFiles},
- {"post-inst-failed",pkgCache::HalfConfigured},
- {"removal-failed",pkgCache::HalfInstalled}};
+ WordList StatusList[] = {{"not-installed",pkgCache::State::NotInstalled},
+ {"unpacked",pkgCache::State::UnPacked},
+ {"half-configured",pkgCache::State::HalfConfigured},
+ {"installed",pkgCache::State::Installed},
+ {"uninstalled",pkgCache::State::UnInstalled},
+ {"half-installed",pkgCache::State::HalfInstalled},
+ {"config-files",pkgCache::State::ConfigFiles},
+ {"post-inst-failed",pkgCache::State::HalfConfigured},
+ {"removal-failed",pkgCache::State::HalfInstalled}};
if (GrabWord(string(Start,I-Start),StatusList,
_count(StatusList),Pkg->CurrentState) == false)
return _error->Error("Malformed 3rd word in the Status line");
@@ -273,8 +273,8 @@ bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg,
version as well. Only if it is actually installed.. Otherwise
the interesting dpkg handling of the status file creates bogus
entries. */
- if (!(Pkg->CurrentState == pkgCache::NotInstalled ||
- Pkg->CurrentState == pkgCache::ConfigFiles))
+ if (!(Pkg->CurrentState == pkgCache::State::NotInstalled ||
+ Pkg->CurrentState == pkgCache::State::ConfigFiles))
{
if (Ver.end() == true)
_error->Warning("Encountered status field in a non-version description");
@@ -330,19 +330,19 @@ const char *debListParser::ParseDepends(const char *Start,const char *Stop,
if (*I == '=')
{
I++;
- Op = pkgCache::LessEq;
+ Op = pkgCache::Dep::LessEq;
break;
}
if (*I == '<')
{
I++;
- Op = pkgCache::Less;
+ Op = pkgCache::Dep::Less;
break;
}
// < is the same as <= and << is really Cs < for some reason
- Op = pkgCache::LessEq;
+ Op = pkgCache::Dep::LessEq;
break;
case '>':
@@ -350,29 +350,29 @@ const char *debListParser::ParseDepends(const char *Start,const char *Stop,
if (*I == '=')
{
I++;
- Op = pkgCache::GreaterEq;
+ Op = pkgCache::Dep::GreaterEq;
break;
}
if (*I == '>')
{
I++;
- Op = pkgCache::Greater;
+ Op = pkgCache::Dep::Greater;
break;
}
// > is the same as >= and >> is really Cs > for some reason
- Op = pkgCache::GreaterEq;
+ Op = pkgCache::Dep::GreaterEq;
break;
case '=':
- Op = pkgCache::Equals;
+ Op = pkgCache::Dep::Equals;
I++;
break;
// HACK around bad package definitions
default:
- Op = pkgCache::Equals;
+ Op = pkgCache::Dep::Equals;
break;
}
@@ -389,13 +389,13 @@ const char *debListParser::ParseDepends(const char *Start,const char *Stop,
else
{
Ver = string();
- Op = pkgCache::NoOp;
+ Op = pkgCache::Dep::NoOp;
}
// Skip whitespace
for (;I != Stop && isspace(*I) != 0; I++);
if (I != Stop && *I == '|')
- Op |= pkgCache::Or;
+ Op |= pkgCache::Dep::Or;
if (I == Stop || *I == ',' || *I == '|')
{
@@ -453,7 +453,7 @@ bool debListParser::ParseProvides(pkgCache::VerIterator Ver)
Start = ParseDepends(Start,Stop,Package,Version,Op);
if (Start == 0)
return _error->Error("Problem parsing Provides line");
- if (Op != pkgCache::NoOp)
+ if (Op != pkgCache::Dep::NoOp)
return _error->Error("Malformed provides line");
if (NewProvides(Ver,Package,Version) == false)
diff --git a/apt-pkg/depcache.cc b/apt-pkg/depcache.cc
new file mode 100644
index 000000000..a7784c0a5
--- /dev/null
+++ b/apt-pkg/depcache.cc
@@ -0,0 +1,903 @@
+// -*- mode: cpp; mode: fold -*-
+// Description /*{{{*/
+// $Id: depcache.cc,v 1.1 1998/07/07 04:17:01 jgg Exp $
+/* ######################################################################
+
+ Dependency Cache - Caches Dependency information.
+
+ ##################################################################### */
+ /*}}}*/
+// Include Files /*{{{*/
+#ifdef __GNUG__
+#pragma implementation "pkglib/depcache.h"
+#endif
+#include <pkglib/depcache.h>
+
+#include <pkglib/version.h>
+#include <pkglib/error.h>
+ /*}}}*/
+
+// DepCache::pkgDepCache - Constructors /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+pkgDepCache::pkgDepCache(MMap &Map) :
+ pkgCache(Map), PkgState(0), DepState(0)
+{
+ if (_error->PendingError() == false)
+ Init();
+}
+ /*}}}*/
+// DepCache::~pkgDepCache - Destructor /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+pkgDepCache::~pkgDepCache()
+{
+ delete [] PkgState;
+ delete [] DepState;
+}
+ /*}}}*/
+// DepCache::ReMap - Regenerate the extra data for the new cache /*{{{*/
+// ---------------------------------------------------------------------
+/* pkgCache's constructors call this function, but because the object is not
+ fully constructed at that point it will not result in this function being
+ called but pkgCache::ReMap will be instead.*/
+bool pkgDepCache::ReMap()
+{
+ if (pkgCache::ReMap() == false)
+ return false;
+
+ return Init();
+}
+ /*}}}*/
+// DepCache::Init - Generate the initial extra structures. /*{{{*/
+// ---------------------------------------------------------------------
+/* This allocats the extension buffers and initializes them. */
+bool pkgDepCache::Init()
+{
+ delete [] PkgState;
+ delete [] DepState;
+ PkgState = new StateCache[Head().PackageCount];
+ DepState = new unsigned char[Head().DependsCount];
+ memset(PkgState,0,sizeof(*PkgState)*Head().PackageCount);
+ memset(DepState,0,sizeof(*DepState)*Head().DependsCount);
+
+ /* Set the current state of everything. In this state all of the
+ packages are kept exactly as is. See AllUpgrade */
+ for (PkgIterator I = PkgBegin(); I.end() != true; I++)
+ {
+ // Find the proper cache slot
+ StateCache &State = PkgState[I->ID];
+ State.iFlags = 0;
+
+ // Figure out the install version
+ State.CandidateVer = GetCandidateVer(I);
+ State.InstallVer = I.CurrentVer();
+ State.Mode = ModeKeep;
+
+ State.Update(I,*this);
+ }
+
+ Update();
+
+ return true;
+}
+ /*}}}*/
+// DepCache::GetCandidateVer - Returns the Candidate install version /*{{{*/
+// ---------------------------------------------------------------------
+/* The default just returns the target version if it exists or the
+ highest version. */
+pkgDepCache::VerIterator pkgDepCache::GetCandidateVer(PkgIterator Pkg)
+{
+ // Try to use an explicit target
+ if (Pkg->TargetVer == 0)
+ {
+ /* Not source versions cannot be a candidate version unless they
+ are already installed */
+ for (VerIterator I = Pkg.VersionList(); I.end() == false; I++)
+ {
+ if (Pkg.CurrentVer() == I)
+ return I;
+ for (VerFileIterator J = I.FileList(); J.end() == false; J++)
+ if ((J.File()->Flags & Flag::NotSource) == 0)
+ return I;
+ }
+
+ return VerIterator(*this,0);
+ }
+ else
+ return Pkg.TargetVer();
+}
+ /*}}}*/
+// DepCache::IsImportantDep - True if the dependency is important /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool pkgDepCache::IsImportantDep(DepIterator Dep)
+{
+ return Dep.IsCritical();
+}
+ /*}}}*/
+
+// DepCache::CheckDep - Checks a single dependency /*{{{*/
+// ---------------------------------------------------------------------
+/* This first checks the dependency against the main target package and
+ then walks along the package provides list and checks if each provides
+ will be installed then checks the provides against the dep. Res will be
+ set to the package which was used to satisfy the dep. */
+bool pkgDepCache::CheckDep(DepIterator Dep,int Type,PkgIterator &Res)
+{
+ Res = Dep.TargetPkg();
+
+ /* Check simple depends. A depends -should- never self match but
+ we allow it anyhow because dpkg does. Technically it is a packaging
+ bug. Conflicts may never self match */
+ if (Dep.TargetPkg() != Dep.ParentPkg() || Dep->Type != Dep::Conflicts)
+ {
+ PkgIterator Pkg = Dep.TargetPkg();
+ // Check the base package
+ if (Type == NowVersion && Pkg->CurrentVer != 0)
+ if (pkgCheckDep(Dep.TargetVer(),
+ Pkg.CurrentVer().VerStr(),Dep->CompareOp) == true)
+ return true;
+
+ if (Type == InstallVersion && PkgState[Pkg->ID].InstallVer != 0)
+ if (pkgCheckDep(Dep.TargetVer(),
+ PkgState[Pkg->ID].InstVerIter(*this).VerStr(),
+ Dep->CompareOp) == true)
+ return true;
+
+ if (Type == CandidateVersion && PkgState[Pkg->ID].CandidateVer != 0)
+ if (pkgCheckDep(Dep.TargetVer(),
+ PkgState[Pkg->ID].CandidateVerIter(*this).VerStr(),
+ Dep->CompareOp) == true)
+ return true;
+ }
+
+ // Check the providing packages
+ PrvIterator P = Dep.TargetPkg().ProvidesList();
+ PkgIterator Pkg = Dep.ParentPkg();
+ for (; P.end() != true; P++)
+ {
+ /* Provides may never be applied against the same package if it is
+ a conflicts. See the comment above. */
+ if (P.OwnerPkg() == Pkg && Dep->Type == Dep::Conflicts)
+ continue;
+
+ // Check if the provides is a hit
+ if (Type == NowVersion)
+ {
+ if (P.OwnerPkg().CurrentVer() != P.OwnerVer())
+ continue;
+ }
+
+ if (Type == InstallVersion)
+ {
+ StateCache &State = PkgState[P.OwnerPkg()->ID];
+ if (State.InstallVer != (Version *)P.OwnerVer())
+ continue;
+ }
+
+ if (Type == CandidateVersion)
+ {
+ StateCache &State = PkgState[P.OwnerPkg()->ID];
+ if (State.CandidateVer != (Version *)P.OwnerVer())
+ continue;
+ }
+
+ // Compare the versions.
+ if (pkgCheckDep(Dep.TargetVer(),P.ProvideVersion(),Dep->CompareOp) == true)
+ {
+ Res = P.OwnerPkg();
+ return true;
+ }
+ }
+
+ return false;
+}
+ /*}}}*/
+// DepCache::AddSizes - Add the packages sizes to the counters /*{{{*/
+// ---------------------------------------------------------------------
+/* Call with Mult = -1 to preform the inverse opration */
+void pkgDepCache::AddSizes(const PkgIterator &Pkg,long Mult)
+{
+ StateCache &P = PkgState[Pkg->ID];
+
+ // Compute the size data
+ if (P.NewInstall() == true)
+ {
+ iUsrSize += Mult*P.InstVerIter(*this)->InstalledSize;
+ iDownloadSize += Mult*P.InstVerIter(*this)->Size;
+ }
+
+ // Upgrading
+ if (Pkg->CurrentVer != 0 && P.InstallVer != (Version *)Pkg.CurrentVer() &&
+ P.InstallVer != 0)
+ {
+ iUsrSize += Mult*(P.InstVerIter(*this)->InstalledSize -
+ Pkg.CurrentVer()->InstalledSize);
+ iDownloadSize += Mult*P.InstVerIter(*this)->Size;
+ }
+
+ // Removing
+ if (Pkg->CurrentVer != 0 && P.InstallVer == 0)
+ iUsrSize -= Mult*Pkg.CurrentVer()->InstalledSize;
+}
+ /*}}}*/
+// DepCache::AddStates - Add the package to the state counter /*{{{*/
+// ---------------------------------------------------------------------
+/* This routine is tricky to use, you must make sure that it is never
+ called twice for the same package. This means the Remove/Add section
+ should be as short as possible and not encompass any code that will
+ calld Remove/Add itself. Remember, dependencies can be circular so
+ while processing a dep for Pkg it is possible that Add/Remove
+ will be called on Pkg */
+void pkgDepCache::AddStates(const PkgIterator &Pkg,int Add)
+{
+ StateCache &State = PkgState[Pkg->ID];
+
+ // The Package is broken
+ if ((State.DepState & DepInstMin) != DepInstMin)
+ iBrokenCount += Add;
+
+ // Bad state
+ if (Pkg.State() != PkgIterator::NeedsNothing)
+ iBadCount += Add;
+
+ // Not installed
+ if (Pkg->CurrentVer == 0)
+ {
+ if (State.Mode == ModeInstall)
+ iInstCount += Add;
+ return;
+ }
+
+ // Installed, no upgrade
+ if (State.Upgradable() == false)
+ {
+ if (State.Mode == ModeDelete)
+ iDelCount += Add;
+ return;
+ }
+
+ // Alll 3 are possible
+ if (State.Mode == ModeDelete)
+ iDelCount += Add;
+ if (State.Mode == ModeKeep)
+ iKeepCount += Add;
+ if (State.Mode == ModeInstall)
+ iInstCount += Add;
+}
+ /*}}}*/
+// DepCache::BuildGroupOrs - Generate the Or group dep data /*{{{*/
+// ---------------------------------------------------------------------
+/* The or group results are stored in the last item of the or group. This
+ allows easy detection of the state of a whole or'd group. */
+void pkgDepCache::BuildGroupOrs(VerIterator const &V)
+{
+ unsigned char Group = 0;
+
+ for (DepIterator D = V.DependsList(); D.end() != true; D++)
+ {
+ // Build the dependency state.
+ unsigned char &State = DepState[D->ID];
+
+ /* Invert for Conflicts. We have to do this twice to get the
+ right sense for a conflicts group */
+ if (D->Type == Dep::Conflicts)
+ State = ~State;
+
+ // Add to the group if we are within an or..
+ Group |= State;
+ State |= Group << 3;
+ if ((D->CompareOp & Dep::Or) != Dep::Or)
+ Group = 0;
+
+ // Invert for Conflicts
+ if (D->Type == Dep::Conflicts)
+ State = ~State;
+ }
+}
+ /*}}}*/
+// DepCache::VersionState - Perform a pass over a dependency list /*{{{*/
+// ---------------------------------------------------------------------
+/* This is used to run over a dependency list and determine the dep
+ state of the list, filtering it through both a Min check and a Policy
+ check. The return result will have SetMin/SetPolicy low if a check
+ fails. It uses the DepState cache for it's computations. */
+unsigned char pkgDepCache::VersionState(DepIterator D,unsigned char Check,
+ unsigned char SetMin,
+ unsigned char SetPolicy)
+{
+ unsigned char Dep = 0xFF;
+
+ while (D.end() != true)
+ {
+ // Compute a single dependency element (glob or)
+ DepIterator Start = D;
+ unsigned char State = 0;
+ for (bool LastOR = true; D.end() == false && LastOR == true; D++)
+ {
+ State |= DepState[D->ID];
+ LastOR = (D->CompareOp & Dep::Or) == Dep::Or;
+ }
+
+ // Minimum deps that must be satisfied to have a working package
+ if (Start.IsCritical() == true)
+ if ((State & Check) != Check)
+ Dep &= ~SetMin;
+
+ // Policy deps that must be satisfied to install the package
+ if (IsImportantDep(Start) == true &&
+ (State & Check) != Check)
+ Dep &= ~SetPolicy;
+ }
+
+ return Dep;
+}
+ /*}}}*/
+// DepCache::DependencyState - Compute the 3 results for a dep /*{{{*/
+// ---------------------------------------------------------------------
+/* This is the main dependency computation bit. It computes the 3 main
+ results for a dependencys, Now, Install and Candidate. Callers must
+ invert the result if dealing with conflicts. */
+unsigned char pkgDepCache::DependencyState(DepIterator &D)
+{
+ unsigned char State = 0;
+
+ if (CheckDep(D,NowVersion) == true)
+ State |= DepNow;
+ if (CheckDep(D,InstallVersion) == true)
+ State |= DepInstall;
+ if (CheckDep(D,CandidateVersion) == true)
+ State |= DepCVer;
+
+ return State;
+}
+ /*}}}*/
+// DepCache::UpdateVerState - Compute the Dep member of the state /*{{{*/
+// ---------------------------------------------------------------------
+/* This determines the combined dependency representation of a package
+ for its two states now and install. This is done by using the pre-generated
+ dependency information. */
+void pkgDepCache::UpdateVerState(PkgIterator Pkg)
+{
+ // Empty deps are always true
+ StateCache &State = PkgState[Pkg->ID];
+ State.DepState = 0xFF;
+
+ // Check the Current state
+ if (Pkg->CurrentVer != 0)
+ {
+ DepIterator D = Pkg.CurrentVer().DependsList();
+ State.DepState &= VersionState(D,DepNow,DepNowMin,DepNowPolicy);
+ }
+
+ /* Check the candidate state. We do not compare against the whole as
+ a candidate state but check the candidate version against the
+ install states */
+ if (State.CandidateVer != 0)
+ {
+ DepIterator D = State.CandidateVerIter(*this).DependsList();
+ State.DepState &= VersionState(D,DepInstall,DepCandMin,DepCandPolicy);
+ }
+
+ // Check target state which can only be current or installed
+ if (State.InstallVer != 0)
+ {
+ DepIterator D = State.InstVerIter(*this).DependsList();
+ State.DepState &= VersionState(D,DepInstall,DepInstMin,DepInstPolicy);
+ }
+}
+ /*}}}*/
+// DepCache::Update - Figure out all the state information /*{{{*/
+// ---------------------------------------------------------------------
+/* This will figure out the state of all the packages and all the
+ dependencies based on the current policy. */
+void pkgDepCache::Update()
+{
+ iUsrSize = 0;
+ iDownloadSize = 0;
+ iDelCount = 0;
+ iInstCount = 0;
+ iKeepCount = 0;
+ iBrokenCount = 0;
+ iBadCount = 0;
+
+ // Perform the depends pass
+ for (PkgIterator I = PkgBegin(); I.end() != true; I++)
+ {
+ for (VerIterator V = I.VersionList(); V.end() != true; V++)
+ {
+ unsigned char Group = 0;
+
+ for (DepIterator D = V.DependsList(); D.end() != true; D++)
+ {
+ // Build the dependency state.
+ unsigned char &State = DepState[D->ID];
+ State = DependencyState(D);;
+
+ // Add to the group if we are within an or..
+ Group |= State;
+ State |= Group << 3;
+ if ((D->CompareOp & Dep::Or) != Dep::Or)
+ Group = 0;
+
+ // Invert for Conflicts
+ if (D->Type == Dep::Conflicts)
+ State = ~State;
+ }
+ }
+
+ // Compute the pacakge dependency state and size additions
+ AddSizes(I);
+ UpdateVerState(I);
+ AddStates(I);
+ }
+}
+ /*}}}*/
+// DepCache::Update - Update the deps list of a package /*{{{*/
+// ---------------------------------------------------------------------
+/* This is a helper for update that only does the dep portion of the scan.
+ It is mainly ment to scan reverse dependencies. */
+void pkgDepCache::Update(DepIterator D)
+{
+ // Update the reverse deps
+ for (;D.end() != true; D++)
+ {
+ unsigned char &State = DepState[D->ID];
+ State = DependencyState(D);
+
+ // Invert for Conflicts
+ if (D->Type == Dep::Conflicts)
+ State = ~State;
+
+ RemoveStates(D.ParentPkg());
+ BuildGroupOrs(D.ParentVer());
+ UpdateVerState(D.ParentPkg());
+ AddStates(D.ParentPkg());
+ }
+}
+ /*}}}*/
+// DepCache::Update - Update the related deps of a package /*{{{*/
+// ---------------------------------------------------------------------
+/* This is called whenever the state of a package changes. It updates
+ all cached dependencies related to this package. */
+void pkgDepCache::Update(PkgIterator const &Pkg)
+{
+ // Recompute the dep of the package
+ RemoveStates(Pkg);
+ UpdateVerState(Pkg);
+ AddStates(Pkg);
+
+ // Update the reverse deps
+ Update(Pkg.RevDependsList());
+
+ // Update the provides map for the current ver
+ if (Pkg->CurrentVer != 0)
+ for (PrvIterator P = Pkg.CurrentVer().ProvidesList();
+ P.end() != true; P++)
+ Update(P.ParentPkg().RevDependsList());
+
+ // Update the provides map for the candidate ver
+ for (PrvIterator P = PkgState[Pkg->ID].CandidateVerIter(*this).ProvidesList();
+ P.end() != true; P++)
+ Update(P.ParentPkg().RevDependsList());
+}
+
+ /*}}}*/
+
+// DepCache::MarkKeep - Put the package in the keep state /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+void pkgDepCache::MarkKeep(PkgIterator const &Pkg,bool Soft)
+{
+ // Simplifies other routines.
+ if (Pkg.end() == true)
+ return;
+
+ /* We changed the soft state all the time so the UI is a bit nicer
+ to use */
+ StateCache &P = PkgState[Pkg->ID];
+ if (Soft == true)
+ P.iFlags |= AutoKept;
+ else
+ P.iFlags &= ~AutoKept;
+
+ // Check that it is not already kept
+ if (P.Mode == ModeKeep)
+ return;
+
+ // We dont even try to keep virtual packages..
+ if (Pkg->VersionList == 0)
+ return;
+
+ P.Flags &= ~Flag::Auto;
+ RemoveSizes(Pkg);
+ RemoveStates(Pkg);
+
+ P.Mode = ModeKeep;
+ if (Pkg->CurrentVer == 0)
+ P.InstallVer = 0;
+ else
+ P.InstallVer = Pkg.CurrentVer();
+
+ AddStates(Pkg);
+
+ Update(Pkg);
+
+ AddSizes(Pkg);
+}
+ /*}}}*/
+// DepCache::MarkDelete - Put the package in the delete state /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+void pkgDepCache::MarkDelete(PkgIterator const &Pkg)
+{
+ // Simplifies other routines.
+ if (Pkg.end() == true)
+ return;
+
+ // Check that it is not already marked for delete
+ StateCache &P = PkgState[Pkg->ID];
+ P.iFlags &= ~AutoKept;
+ if (P.Mode == ModeDelete || P.InstallVer == 0)
+ return;
+
+ // We dont even try to delete virtual packages..
+ if (Pkg->VersionList == 0)
+ return;
+
+ RemoveSizes(Pkg);
+ RemoveStates(Pkg);
+
+ P.Mode = ModeDelete;
+ P.InstallVer = 0;
+ P.Flags &= Flag::Auto;
+
+ AddStates(Pkg);
+ Update(Pkg);
+ AddSizes(Pkg);
+}
+ /*}}}*/
+// DepCache::MarkInstall - Put the package in the install state /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst)
+{
+ // Simplifies other routines.
+ if (Pkg.end() == true)
+ return;
+
+ /* Check that it is not already marked for install and that it can be
+ installed */
+ StateCache &P = PkgState[Pkg->ID];
+ P.iFlags &= ~AutoKept;
+ if (P.InstBroken() == false && (P.Mode == ModeInstall ||
+ P.CandidateVer == (Version *)Pkg.CurrentVer()))
+ {
+ if (P.CandidateVer == (Version *)Pkg.CurrentVer() && P.InstallVer == 0)
+ MarkKeep(Pkg);
+ return;
+ }
+
+ // We dont even try to install virtual packages..
+ if (Pkg->VersionList == 0)
+ return;
+
+ /* Target the candidate version and remove the autoflag. We reset the
+ autoflag below if this was called recursively. Otherwise the user
+ should have the ability to de-auto a package by changing its state */
+ RemoveSizes(Pkg);
+ RemoveStates(Pkg);
+
+ P.Mode = ModeInstall;
+ P.InstallVer = P.CandidateVer;
+ P.Flags &= ~Flag::Auto;
+ if (P.CandidateVer == (Version *)Pkg.CurrentVer())
+ P.Mode = ModeKeep;
+
+ AddStates(Pkg);
+ Update(Pkg);
+ AddSizes(Pkg);
+
+ if (AutoInst == false)
+ return;
+
+ DepIterator Dep = P.InstVerIter(*this).DependsList();
+ for (; Dep.end() != true;)
+ {
+ // Grok or groups
+ DepIterator Start = Dep;
+ bool Result = true;
+ for (bool LastOR = true; Dep.end() == false && LastOR == true; Dep++)
+ {
+ LastOR = (Dep->CompareOp & Dep::Or) == Dep::Or;
+
+ if ((DepState[Dep->ID] & DepInstall) == DepInstall)
+ Result = false;
+ }
+
+ // Dep is satisfied okay.
+ if (Result == false)
+ continue;
+
+ /* Check if this dep should be consider for install. If it is a user
+ defined important dep and we are installed a new package then
+ it will be installed. Otherwise we only worry about critical deps */
+ if (IsImportantDep(Start) == false)
+ continue;
+ if (Pkg->CurrentVer != 0 && Start.IsCritical() == false)
+ continue;
+
+ // Now we have to take action...
+ PkgIterator P = Start.SmartTargetPkg();
+ if ((DepState[Start->ID] & DepCVer) == DepCVer)
+ {
+ MarkInstall(P,true);
+
+ // Set the autoflag, after MarkInstall because MarkInstall unsets it
+ if (P->CurrentVer == 0)
+ PkgState[P->ID].Flags |= Flag::Auto;
+
+ continue;
+ }
+
+ // For conflicts we just de-install the package and mark as auto
+ if (Start->Type == Dep::Conflicts)
+ {
+ Version **List = Start.AllTargets();
+ for (Version **I = List; *I != 0; I++)
+ {
+ VerIterator Ver(*this,*I);
+ PkgIterator Pkg = Ver.ParentPkg();
+
+ MarkDelete(Pkg);
+ PkgState[Pkg->ID].Flags |= Flag::Auto;
+ }
+ delete [] List;
+ continue;
+ }
+ }
+}
+ /*}}}*/
+
+#if 0
+// DepCache::ResolveConflicts - Figure the auto upgrades /*{{{*/
+// ---------------------------------------------------------------------
+/* This routine attempts to resolve conflicts generated by automatic
+ upgrading. It is known as 'Stage 1' but that name isn't as proper anymore.
+
+ It's most important function is during the initial load of APT. The
+ loading code will mark every package for upgrade to it's candidate version
+ and then call this routine. This routine will then 'soft keep' every
+ package that causes conflict, is conflicted, or so on. It is a bit
+ agressive in that it may unselect more packages in some odd cases
+ than are strictly necessary but in the case where no packages were
+ conflicting before it will always produce a system with no packages
+ conflicting after.
+
+ This routine is also used during state changes that require autoupgrade
+ scanning. That is, if a new package is marked for install then all packages
+ that have been soft kept are reconsidered for upgrade.
+
+ It is called with state information about what can be un-upgraded and
+ what the pre-upgrade install state was. It is expected that the caller
+ has already marked the desired packages to the install state. Bit 0 is
+ the original install state and Bit 1 is controls whether the package
+ should be touched.
+*/
+void pkgDepCache::ResolveConflicts(unsigned char *Touched)
+{
+ bool Again = false;
+ do
+ {
+ Again = false;
+ for (PkgIterator I = PkgBegin(); I.end() != true; I++)
+ {
+ // The package will install OK
+ if ((PkgState[I->ID].DepState & DepInstMin) == DepInstMin)
+ continue;
+
+ /* The package was broken before and this upgrade will not
+ make things better. We simply mark the package for keep
+ and assume an upgrade attempt will be hopeless. This might
+ not be ideal. */
+ if ((Touched[I->ID] & (1 << 0)) != (1 << 0))
+ {
+ // The package isnt to be touched
+ if ((Touched[I->ID] & (1 << 1)) == (1 << 1))
+ MarkKeep(I,true);
+
+ continue;
+ }
+
+ // Check to see if not upgrading it will solve the problem
+ if (I->CurrentVer != 0)
+ {
+ // The package isnt to be touched
+ if ((Touched[I->ID] & (1 << 1)) == (1 << 1))
+ {
+ if (PkgState[I->ID].Mode != ModeKeep)
+ Again = true;
+
+ MarkKeep(I,true);
+ }
+
+ /* Check if the package is sill broken. If so then we cant leave
+ it as is and get a working system. Lets try marking some
+ depends for 'keep'. This is brutal, it keeps everything in
+ sight to fix the problem. */
+ DepIterator D = I.CurrentVer().DependsList();
+ for (;(PkgState[I->ID].DepState & DepInstMin) != DepInstMin &&
+ D.end() != true; D++)
+ {
+ // We only worry about critical deps.
+ if (D.IsCritical() != true)
+ continue;
+
+ unsigned char State = DepState[D->ID];
+
+ // This dep never was set before so we dont need to set it now
+ if ((State & DepNow) != DepNow)
+ continue;
+
+ // The dep is okay now no worries.
+ if ((State & DepInstall) == DepInstall)
+ continue;
+
+ // Locate a target to keep
+ PkgIterator P(*this);
+ if (CheckDep(D,NowVersion,P) == true)
+ {
+ // We cant touch this package
+ if ((Touched[P->ID] & (1 << 1)) == (1 << 1))
+ MarkKeep(P,true);
+ }
+ }
+ }
+ }
+ }
+ while (Again == true);
+}
+ /*}}}*/
+// DepCache::PromoteAutoKeep - Gentler version of the above /*{{{*/
+// ---------------------------------------------------------------------
+/* This is used when installing packages, all it does is attempt to promote
+ everything that has been auto-kept. It simply promotes everything
+ irregardless of it having a chance to work and then runs ResolveConflicts
+ on the result. This allows circular depends loops to work but isn't
+ terribly fast. */
+void pkgDepCache::PromoteAutoKeep()
+{
+ /* Initialize the touchd array. Bit 0 is the old install state bit 1
+ is the touch value */
+ unsigned char *Touch = new unsigned char[Head().PackageCount];
+ for (unsigned int I = 0; I != Head().PackageCount; I++)
+ {
+ if ((PkgState[I].DepState & DepInstMin) == DepInstMin)
+ Touch[I] = 1 << 0;
+ else
+ Touch[I] = 0;
+ }
+
+ // This allows circular depends to work
+ for (PkgIterator I = PkgBegin(); I.end() != true; I++)
+ {
+ /* It wasnt installed before or it is not autokept or it is not
+ upgradeable */
+ StateCache &P = PkgState[I->ID];
+ if (I->CurrentVer == 0 || P.Mode != ModeKeep || I->VersionList == 0 ||
+ P.CandidateVer == (Version *)I.CurrentVer() ||
+ (P.iFlags & AutoKept) != AutoKept)
+ continue;
+
+ P.Mode = ModeInstall;
+ P.InstallVer = P.CandidateVer;
+ if (P.CandidateVer == (Version *)I.CurrentVer())
+ P.Mode = ModeKeep;
+
+ // Okay autoupgrade it.
+ Touch[I->ID] |= 1 << 1;
+ }
+
+ Update();
+ ResolveConflicts(Touch);
+
+ delete [] Touch;
+}
+ /*}}}*/
+// DepCache::AllUpgrade - Try to upgrade everything /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+void pkgDepCache::AllUpgrade()
+{
+ // Set everything to an upgrade mode
+ for (PkgIterator I = PkgBegin(); I.end() != true; I++)
+ {
+ StateCache &State = PkgState[I->ID];
+
+ /* We dont upgrade packages marked for deletion or that are
+ not installed or that don't have an upgrade */
+ if (State.Mode == ModeDelete || I->CurrentVer == 0 ||
+ (Version *)I.CurrentVer() == State.CandidateVer)
+ continue;
+
+ // Set the state to upgrade
+ State.iFlags = 0;
+ State.Mode = ModeInstall;
+ State.InstallVer = State.CandidateVer;
+ if (State.CandidateVer == (Version *)I.CurrentVer())
+ State.Mode = ModeKeep;
+
+ // Do not upgrade things that have the hold flag set.
+ if (I->SelectedState == State::Hold)
+ {
+ State.InstallVer = I.CurrentVer();
+ State.Mode = ModeKeep;
+ }
+ State.Update(I,*this);
+ }
+
+ Update();
+
+ /* Initialize the touchd array. Bit 0 is the old install state bit 1
+ is the touch value */
+ unsigned char *Touch = new unsigned char[Head().PackageCount];
+ for (unsigned int I = 0; I != Head().PackageCount; I++)
+ {
+ if ((PkgState[I].DepState & DepNowMin) == DepNowMin)
+ Touch[I] = (1 << 0) | (1 << 1);
+ else
+ Touch[I] = 1 << 1;
+ }
+
+ // Now downgrade everything that is broken
+ ResolveConflicts(Touch);
+ delete [] Touch;
+}
+ /*}}}*/
+#endif
+
+// StateCache::Update - Compute the various static display things /*{{{*/
+// ---------------------------------------------------------------------
+/* This is called whenever the Candidate version changes. */
+void pkgDepCache::StateCache::Update(PkgIterator Pkg,pkgCache &Cache)
+{
+ // Some info
+ VerIterator Ver = CandidateVerIter(Cache);
+
+ // Use a null string or the version string
+ if (Ver.end() == true)
+ CandVersion = "";
+ else
+ CandVersion = Ver.VerStr();
+
+ // Find the current version
+ CurVersion = "";
+ if (Pkg->CurrentVer != 0)
+ CurVersion = Pkg.CurrentVer().VerStr();
+
+ // Strip off the epochs for display
+ CurVersion = StripEpoch(CurVersion);
+ CandVersion = StripEpoch(CandVersion);
+
+ // Figure out if its up or down or equal
+ Status = Ver.CompareVer(Pkg.CurrentVer());
+ if (Pkg->CurrentVer == 0 || Pkg->VersionList == 0 || CandidateVer == 0)
+ Status = 2;
+}
+ /*}}}*/
+// StateCache::StripEpoch - Remove the epoch specifier from the version /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+const char *pkgDepCache::StateCache::StripEpoch(const char *Ver)
+{
+ if (Ver == 0)
+ return 0;
+
+ // Strip any epoch
+ for (const char *I = Ver; *I != 0; I++)
+ if (*I == ':')
+ return I + 1;
+ return Ver;
+}
+ /*}}}*/
diff --git a/apt-pkg/depcache.h b/apt-pkg/depcache.h
new file mode 100644
index 000000000..222e34425
--- /dev/null
+++ b/apt-pkg/depcache.h
@@ -0,0 +1,189 @@
+// -*- mode: cpp; mode: fold -*-
+// Description /*{{{*/
+// $Id: depcache.h,v 1.1 1998/07/07 04:17:01 jgg Exp $
+/* ######################################################################
+
+ DepCache - Dependency Extension data for the cache
+
+ This class stores the cache data and a set of extension structures for
+ monitoring the current state of all the packages. It also generates and
+ caches the 'install' state of many things. This refers to the state of the
+ package after an install has been run.
+
+ The StateCache::State field can be -1,0,1,2 which is <,=,>,no current.
+ StateCache::Mode is which of the 3 fields is active.
+
+ This structure is important to support the readonly status of the cache
+ file. When the data is saved the cache will be refereshed from our
+ internal rep and written to disk. Then the actual persistant data
+ files will be put on the disk.
+
+ Each dependency is compared against 3 target versions to produce to
+ 3 dependency results.
+ Now - Compared using the Currently install version
+ Install - Compared using the install version (final state)
+ CVer - (Candidate Verion) Compared using the Candidate Version
+ The candidate and now results are used to decide wheather a package
+ should be automatically installed or if it should be left alone.
+
+ Remember, the Candidate Version is selected based on the distribution
+ settings for the Package. The Install Version is selected based on the
+ state (Delete, Keep, Install) field and can be either the Current Version
+ or the Candidate version.
+
+ The Candidate version is what is shown the 'Install Version' field.
+
+ ##################################################################### */
+ /*}}}*/
+// Header section: pkglib
+#ifndef PKGLIB_DEPCACHE_H
+#define PKGLIB_DEPCACHE_H
+
+#ifdef __GNUG__
+#pragma interface "pkglib/depcache.h"
+#endif
+
+#include <pkglib/pkgcache.h>
+
+class pkgDepCache : public pkgCache
+{
+ public:
+
+ // These flags are used in DepState
+ enum DepFlags {DepNow = (1 << 0),DepInstall = (1 << 1),DepCVer = (1 << 2),
+ DepGNow = (1 << 3),DepGInstall = (1 << 4),DepGCVer = (1 << 5)};
+
+ // These flags are used in StateCache::DepState
+ enum DepStateFlags {DepNowPolicy = (1 << 0), DepNowMin = (1 << 1),
+ DepInstPolicy = (1 << 2), DepInstMin = (1 << 3),
+ DepCandPolicy = (1 << 4), DepCandMin = (1 << 5)};
+
+ // These flags are used in StateCache::iFlags
+ enum InternalFlags {AutoKept = (1 << 0)};
+
+ enum VersionTypes {NowVersion, InstallVersion, CandidateVersion};
+ enum ModeList {ModeDelete = 0, ModeKeep = 1, ModeInstall = 2};
+ struct StateCache
+ {
+ // Epoch stripped text versions of the two version fields
+ const char *CandVersion;
+ const char *CurVersion;
+
+ // Pointer to the candidate install version.
+ Version *CandidateVer;
+
+ // Pointer to the install version.
+ Version *InstallVer;
+
+ // Various tree indicators
+ signed char Status; // -1,0,1,2
+ unsigned char Mode; // ModeList
+ unsigned char DepState; // DepState Flags
+
+ // Copy of Package::Flags
+ unsigned short Flags;
+ unsigned short iFlags; // Internal flags
+
+ // Update of candidate version
+ const char *StripEpoch(const char *Ver);
+ void Update(PkgIterator Pkg,pkgCache &Cache);
+
+ // Various test members for the current status of the package
+ inline bool NewInstall() const {return Status == 2 && Mode == ModeInstall;};
+ inline bool Delete() const {return Mode == ModeDelete;};
+ inline bool Keep() const {return Mode == ModeKeep;};
+ inline bool Upgrade() const {return Status > 0 && Mode == ModeInstall;};
+ inline bool Upgradable() const {return Status == 1;};
+ inline bool Downgrade() const {return Status < 0;};
+ inline bool Held() const {return Status != 0 && Keep();};
+ inline bool NowBroken() const {return (DepState & DepNowMin) != DepNowMin;};
+ inline bool InstBroken() const {return (DepState & DepInstMin) != DepInstMin;};
+ inline bool Install() const {return Mode == ModeInstall;};
+ inline VerIterator InstVerIter(pkgCache &Cache)
+ {return VerIterator(Cache,InstallVer);};
+ inline VerIterator CandidateVerIter(pkgCache &Cache)
+ {return VerIterator(Cache,CandidateVer);};
+ };
+
+ // Helper functions
+ void BuildGroupOrs(VerIterator const &V);
+ void UpdateVerState(PkgIterator Pkg);
+
+ bool Init();
+
+ protected:
+
+ // State information
+ StateCache *PkgState;
+ unsigned char *DepState;
+
+ long iUsrSize;
+ long iDownloadSize;
+ long iInstCount;
+ long iDelCount;
+ long iKeepCount;
+ long iBrokenCount;
+ long iBadCount;
+
+ // Check for a matching provides
+ bool CheckDep(DepIterator Dep,int Type,PkgIterator &Res);
+ inline bool CheckDep(DepIterator Dep,int Type)
+ {
+ PkgIterator Res(*this);
+ return CheckDep(Dep,Type,Res);
+ }
+
+ // Computes state information for deps and versions (w/o storing)
+ unsigned char DependencyState(DepIterator &D);
+ unsigned char VersionState(DepIterator D,unsigned char Check,
+ unsigned char SetMin,
+ unsigned char SetPolicy);
+
+ // Recalculates various portions of the cache, call after changing something
+ void Update(DepIterator Dep); // Mostly internal
+ void Update(PkgIterator const &P);
+
+ // Count manipulators
+ void AddSizes(const PkgIterator &Pkg,long Mult = 1);
+ inline void RemoveSizes(const PkgIterator &Pkg) {AddSizes(Pkg,-1);};
+ void AddStates(const PkgIterator &Pkg,int Add = 1);
+ inline void RemoveStates(const PkgIterator &Pkg) {AddStates(Pkg,-1);};
+
+ public:
+
+ // Policy implementation
+ virtual VerIterator GetCandidateVer(PkgIterator Pkg);
+ virtual bool IsImportantDep(DepIterator Dep);
+
+ // Accessors
+ inline StateCache &operator [](PkgIterator const &I) {return PkgState[I->ID];};
+ inline unsigned char &operator [](DepIterator const &I) {return DepState[I->ID];};
+
+ // Manipulators
+ void MarkKeep(PkgIterator const &Pkg,bool Soft = false);
+ void MarkDelete(PkgIterator const &Pkg);
+ void MarkInstall(PkgIterator const &Pkg,bool AutoInst = true);
+
+ // This is for debuging
+ void Update();
+
+ // Dep Processing for AutoKeep
+ void ResolveConflicts(unsigned char *Touched);
+
+ // Hook to keep the extra data in sync
+ virtual bool ReMap();
+
+ // Size queries
+ inline long UsrSize() {return iUsrSize;};
+ inline long DebSize() {return iDownloadSize;};
+ inline long DelCount() {return iDelCount;};
+ inline long KeepCount() {return iKeepCount;};
+ inline long InstCount() {return iInstCount;};
+ inline long BrokenCount() {return iBrokenCount;};
+ inline long BadCount() {return iBadCount;};
+
+ pkgDepCache(MMap &Map);
+ virtual ~pkgDepCache();
+};
+
+#endif
diff --git a/apt-pkg/orderlist.cc b/apt-pkg/orderlist.cc
new file mode 100644
index 000000000..f79a063bd
--- /dev/null
+++ b/apt-pkg/orderlist.cc
@@ -0,0 +1,829 @@
+// -*- mode: cpp; mode: fold -*-
+// Description /*{{{*/
+// $Id: orderlist.cc,v 1.1 1998/07/07 04:17:01 jgg Exp $
+/* ######################################################################
+
+ Order List - Represents and Manipulates an ordered list of packages.
+
+ A list of packages can be ordered by a number of conflicting criteria
+ each given a specific priority. Each package also has a set of flags
+ indicating some usefull things about it that are derived in the
+ course of sorting. The pkgPackageManager class uses this class for
+ all of it's installation ordering needs.
+
+ This is a modified version of Manoj's Routine B. It consists of four
+ independent ordering algorithms that can be applied at for different
+ points in the ordering. By appling progressivly fewer ordering
+ operations it is possible to give each consideration it's own
+ priority and create an order that satisfies the lowest applicable
+ consideration.
+
+ The rules for unpacking ordering are:
+ 1) Unpacking ignores Depends: on all packages
+ 2) Unpacking requires Conflicts: on -ALL- packages to be satisfied
+ 3) Unpacking requires PreDepends: on this package only to be satisfied
+ 4) Removing requires that no packages depend on the package to be
+ removed.
+
+ And the rule for configuration ordering is:
+ 1) Configuring requires that the Depends: of the package be satisfied
+ Conflicts+PreDepends are ignored because unpacking says they are
+ already correct [exageration, it does check but we need not be
+ concerned]
+
+ And some features that are valuable for unpacking ordering.
+ f1) Unpacking a new package should advoid breaking dependencies of
+ configured packages
+ f2) Removal should not require a force, corrolory of f1
+ f3) Unpacking should order by depends rather than fall back to random
+ ordering.
+
+ Each of the features can be enabled in the sorting routine at an
+ arbitary priority to give quite abit of control over the final unpacking
+ order.
+
+ The rules listed above my never be violated and are called Critical.
+ When a critical rule is violated then a loop condition is recorded
+ and will have to be delt with in the caller.
+
+ ##################################################################### */
+ /*}}}*/
+// Include Files /*{{{*/
+#ifdef __GNUG__
+#pragma implementation "pkglib/orderlist.h"
+#endif
+#include <pkglib/orderlist.h>
+#include <pkglib/depcache.h>
+#include <pkglib/error.h>
+#include <pkglib/version.h>
+ /*}}}*/
+
+pkgOrderList *pkgOrderList::Me = 0;
+
+// OrderList::pkgOrderList - Constructor /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+pkgOrderList::pkgOrderList(pkgDepCache &Cache) : Cache(Cache)
+{
+ Primary = 0;
+ Secondary = 0;
+ RevDepends = 0;
+ Remove = 0;
+ LoopCount = -1;
+
+ /* Construct the arrays, egcs 1.0.1 bug requires the package count
+ hack */
+ unsigned long Size = Cache.HeaderP->PackageCount;
+ Flags = new unsigned char[Size];
+ End = List = new Package *[Size];
+ memset(Flags,0,sizeof(*Flags)*Size);
+}
+ /*}}}*/
+// OrderList::~pkgOrderList - Destructor /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+pkgOrderList::~pkgOrderList()
+{
+ delete [] List;
+ delete [] Flags;
+}
+ /*}}}*/
+
+// OrderList::DoRun - Does an order run /*{{{*/
+// ---------------------------------------------------------------------
+/* The caller is expeted to have setup the desired probe state */
+bool pkgOrderList::DoRun()
+{
+ // Temp list
+ unsigned long Size = Cache.HeaderP->PackageCount;
+ Package **NList = new Package *[Size];
+
+ Depth = 0;
+ WipeFlags(Added | AddPending | Loop | InList);
+
+ for (iterator I = List; I != End; I++)
+ Flag(*I,InList);
+
+ // Rebuild the main list into the temp list.
+ iterator OldEnd = End;
+ End = NList;
+ for (iterator I = List; I != OldEnd; I++)
+ if (VisitNode(PkgIterator(Cache,*I)) == false)
+ {
+ End = OldEnd;
+ delete [] NList;
+ return false;
+ }
+
+ // Swap the main list to the new list
+ delete [] List;
+ List = NList;
+ return true;
+}
+ /*}}}*/
+// OrderList::OrderCritical - Perform critical unpacking ordering /*{{{*/
+// ---------------------------------------------------------------------
+/* This performs predepends and immediate configuration ordering only.
+ This is termed critical unpacking ordering. Any loops that form are
+ fatal and indicate that the packages cannot be installed. */
+bool pkgOrderList::OrderCritical()
+{
+ Primary = &DepUnPackPre;
+ Secondary = 0;
+ RevDepends = 0;
+ Remove = 0;
+ LoopCount = 0;
+
+ // Sort
+ Me = this;
+ qsort(List,End - List,sizeof(*List),&OrderCompareB);
+
+ if (DoRun() == false)
+ return false;
+
+ if (LoopCount != 0)
+ return _error->Error("Fatal, predepends looping detected");
+ return true;
+}
+ /*}}}*/
+// OrderList::OrderUnpack - Perform complete unpacking ordering /*{{{*/
+// ---------------------------------------------------------------------
+/* This performs complete unpacking ordering and creates an order that is
+ suitable for unpacking */
+bool pkgOrderList::OrderUnpack()
+{
+ Primary = &DepUnPackCrit;
+ Secondary = &DepConfigure;
+ RevDepends = &DepUnPackDep;
+ Remove = &DepRemove;
+ LoopCount = -1;
+
+ // Sort
+ Me = this;
+ qsort(List,End - List,sizeof(*List),&OrderCompareA);
+
+ if (DoRun() == false)
+ return false;
+
+ Secondary = 0;
+ if (DoRun() == false)
+ return false;
+
+ LoopCount = 0;
+ RevDepends = 0;
+ Remove = 0; // Otherwise the libreadline remove problem occures
+ if (DoRun() == false)
+ return false;
+
+ LoopCount = 0;
+ Primary = &DepUnPackPre;
+ if (DoRun() == false)
+ return false;
+
+/* cout << "----------END" << endl;
+
+ for (iterator I = List; I != End; I++)
+ {
+ PkgIterator P(Cache,*I);
+ cout << P.Name() << endl;
+ }*/
+
+ return true;
+}
+ /*}}}*/
+// OrderList::OrderConfigure - Perform configuration ordering /*{{{*/
+// ---------------------------------------------------------------------
+/* This orders by depends only and produces an order which is suitable
+ for configuration */
+bool pkgOrderList::OrderConfigure()
+{
+ Primary = &DepConfigure;
+ Secondary = 0;
+ RevDepends = 0;
+ Remove = 0;
+ LoopCount = -1;
+ return DoRun();
+}
+ /*}}}*/
+
+// OrderList::Score - Score the package for sorting /*{{{*/
+// ---------------------------------------------------------------------
+/* Higher scores order earlier */
+int pkgOrderList::Score(PkgIterator Pkg)
+{
+ // Removal is always done first
+ if (Cache[Pkg].Delete() == true)
+ return 200;
+
+ int Score = 0;
+ if ((Pkg->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
+ Score += 100;
+
+ for (DepIterator D = Cache[Pkg].InstVerIter(Cache).DependsList();
+ D.end() == false; D++)
+ if (D->Type == pkgCache::Dep::PreDepends)
+ {
+ Score += 50;
+ break;
+ }
+
+ // Important Required Standard Optional Extra
+ signed short PrioMap[] = {0,5,4,3,1,0};
+ if (Cache[Pkg].InstVerIter(Cache)->Priority <= 5)
+ Score += PrioMap[Cache[Pkg].InstVerIter(Cache)->Priority];
+ return Score;
+}
+ /*}}}*/
+// OrderList::FileCmp - Compare by package file /*{{{*/
+// ---------------------------------------------------------------------
+/* This compares by the package file that the install version is in. */
+int pkgOrderList::FileCmp(PkgIterator A,PkgIterator B)
+{
+ if (Cache[A].Delete() == true && Cache[B].Delete() == true)
+ return 0;
+ if (Cache[A].Delete() == true)
+ return -1;
+ if (Cache[B].Delete() == true)
+ return 1;
+
+ if (Cache[A].InstVerIter(Cache).FileList().end() == true)
+ return -1;
+ if (Cache[A].InstVerIter(Cache).FileList().end() == true)
+ return 1;
+
+ pkgCache::PackageFile *FA = Cache[A].InstVerIter(Cache).FileList().File();
+ pkgCache::PackageFile *FB = Cache[B].InstVerIter(Cache).FileList().File();
+ if (FA < FB)
+ return -1;
+ if (FA > FB)
+ return 1;
+ return 0;
+}
+ /*}}}*/
+// OrderList::OrderCompareA - Order the installation by op /*{{{*/
+// ---------------------------------------------------------------------
+/* This provides a first-pass sort of the list and gives a decent starting
+ point for further complete ordering. It is used by OrderUnpack only */
+int pkgOrderList::OrderCompareA(const void *a, const void *b)
+{
+ PkgIterator A(Me->Cache,*(Package **)a);
+ PkgIterator B(Me->Cache,*(Package **)b);
+
+ if (A.State() != pkgCache::PkgIterator::NeedsNothing &&
+ B.State() == pkgCache::PkgIterator::NeedsNothing)
+ return -1;
+
+ if (A.State() == pkgCache::PkgIterator::NeedsNothing &&
+ B.State() != pkgCache::PkgIterator::NeedsNothing)
+ return 1;
+
+ int ScoreA = Me->Score(A);
+ int ScoreB = Me->Score(B);
+ if (ScoreA > ScoreB)
+ return -1;
+
+ if (ScoreA < ScoreB)
+ return 1;
+
+ return strcmp(A.Name(),B.Name());
+}
+ /*}}}*/
+// OrderList::OrderCompareB - Order the installation by source /*{{{*/
+// ---------------------------------------------------------------------
+/* This orders by installation source. This is usefull to handle
+ inter-source breaks */
+int pkgOrderList::OrderCompareB(const void *a, const void *b)
+{
+ PkgIterator A(Me->Cache,*(Package **)a);
+ PkgIterator B(Me->Cache,*(Package **)b);
+
+ if (A.State() != pkgCache::PkgIterator::NeedsNothing &&
+ B.State() == pkgCache::PkgIterator::NeedsNothing)
+ return -1;
+
+ if (A.State() == pkgCache::PkgIterator::NeedsNothing &&
+ B.State() != pkgCache::PkgIterator::NeedsNothing)
+ return 1;
+
+ int F = Me->FileCmp(A,B);
+ if (F != 0)
+ {
+ if (F > 0)
+ return -1;
+ return 1;
+ }
+
+ int ScoreA = Me->Score(A);
+ int ScoreB = Me->Score(B);
+ if (ScoreA > ScoreB)
+ return -1;
+
+ if (ScoreA < ScoreB)
+ return 1;
+
+ return strcmp(A.Name(),B.Name());
+}
+ /*}}}*/
+
+// OrderList::VisitDeps - Visit forward install dependencies /*{{{*/
+// ---------------------------------------------------------------------
+/* This calls the dependency function for the normal forwards dependencies
+ of the package */
+bool pkgOrderList::VisitDeps(DepFunc F,PkgIterator Pkg)
+{
+ if (F == 0 || Pkg.end() == true || Cache[Pkg].InstallVer == 0)
+ return true;
+
+ return (this->*F)(Cache[Pkg].InstVerIter(Cache).DependsList());
+}
+ /*}}}*/
+// OrderList::VisitRDeps - Visit reverse dependencies /*{{{*/
+// ---------------------------------------------------------------------
+/* This calls the dependency function for all of the normal reverse depends
+ of the package */
+bool pkgOrderList::VisitRDeps(DepFunc F,PkgIterator Pkg)
+{
+ if (F == 0 || Pkg.end() == true)
+ return true;
+
+ return (this->*F)(Pkg.RevDependsList());
+}
+ /*}}}*/
+// OrderList::VisitRProvides - Visit provides reverse dependencies /*{{{*/
+// ---------------------------------------------------------------------
+/* This calls the dependency function for all reverse dependencies
+ generated by the provides line on the package. */
+bool pkgOrderList::VisitRProvides(DepFunc F,VerIterator Ver)
+{
+ if (F == 0 || Ver.end() == true)
+ return true;
+
+ bool Res = true;
+ for (PrvIterator P = Ver.ProvidesList(); P.end() == false; P++)
+ Res &= (this->*F)(P.ParentPkg().RevDependsList());
+ return true;
+}
+ /*}}}*/
+// OrderList::VisitProvides - Visit all of the providing packages /*{{{*/
+// ---------------------------------------------------------------------
+/* This routine calls visit on all providing packages. */
+bool pkgOrderList::VisitProvides(DepIterator D)
+{
+ Version **List = D.AllTargets();
+ for (Version **I = List; *I != 0; I++)
+ {
+ VerIterator Ver(Cache,*I);
+ PkgIterator Pkg = Ver.ParentPkg();
+
+ if (Cache[Pkg].Keep() == true)
+ continue;
+
+ if (D->Type != pkgCache::Dep::Conflicts && Cache[Pkg].InstallVer != *I)
+ continue;
+
+ if (D->Type == pkgCache::Dep::Conflicts && (Version *)Pkg.CurrentVer() != *I)
+ continue;
+
+ if (VisitNode(Pkg) == false)
+ {
+ delete [] List;
+ return false;
+ }
+ }
+ delete [] List;
+ return true;
+}
+ /*}}}*/
+// OrderList::VisitNode - Recursive ordering director /*{{{*/
+// ---------------------------------------------------------------------
+/* This is the core ordering routine. It calls the set dependency
+ consideration functions which then potentialy call this again. Finite
+ depth is achived through the colouring mechinism. */
+bool pkgOrderList::VisitNode(PkgIterator Pkg)
+{
+ // Looping or irrelevent.
+ if (Pkg.end() == true || IsFlag(Pkg,Added) == true ||
+ IsFlag(Pkg,AddPending) == true || IsFlag(Pkg,InList) == false)
+ return true;
+
+/* for (int j = 0; j != Depth; j++) cout << ' ';
+ cout << "Visit " << Pkg.Name() << endl;*/
+ Depth++;
+
+ // Color grey
+ Flag(Pkg,AddPending);
+
+ DepFunc Old = Primary;
+
+ // Perform immedate configuration of the package if so flagged.
+ if (IsFlag(Pkg,Immediate) == true && Primary != &DepUnPackPre)
+ Primary = &DepUnPackPreD;
+
+ bool Res = true;
+ if (Cache[Pkg].Delete() == false)
+ {
+ // Primary
+ Res &= Res && VisitDeps(Primary,Pkg);
+ Res &= Res && VisitRDeps(Primary,Pkg);
+ Res &= Res && VisitRProvides(Primary,Pkg.CurrentVer());
+ Res &= Res && VisitRProvides(Primary,Cache[Pkg].InstVerIter(Cache));
+
+ // RevDep
+ Res &= Res && VisitRDeps(RevDepends,Pkg);
+ Res &= Res && VisitRProvides(RevDepends,Pkg.CurrentVer());
+ Res &= Res && VisitRProvides(RevDepends,Cache[Pkg].InstVerIter(Cache));
+
+ // Secondary
+ Res &= Res && VisitDeps(Secondary,Pkg);
+ Res &= Res && VisitRDeps(Secondary,Pkg);
+ Res &= Res && VisitRProvides(Secondary,Pkg.CurrentVer());
+ Res &= Res && VisitRProvides(Secondary,Cache[Pkg].InstVerIter(Cache));
+ }
+ else
+ {
+ // RevDep
+ Res &= Res && VisitRDeps(Remove,Pkg);
+ Res &= Res && VisitRProvides(Remove,Pkg.CurrentVer());
+ }
+
+ if (IsFlag(Pkg,Added) == false)
+ {
+ Flag(Pkg,Added,Added | AddPending);
+ *End = Pkg;
+ End++;
+ }
+
+ Primary = Old;
+ Depth--;
+
+/* for (int j = 0; j != Depth; j++) cout << ' ';
+ cout << "Leave " << Pkg.Name() << ' ' << IsFlag(Pkg,Added) << ',' << IsFlag(Pkg,AddPending) << endl;*/
+
+ return true;
+}
+ /*}}}*/
+
+// OrderList::DepUnPackCrit - Critical UnPacking ordering /*{{{*/
+// ---------------------------------------------------------------------
+/* Critical unpacking ordering strives to satisfy Conflicts: and
+ PreDepends: only. When a prdepends is encountered the Primary
+ DepFunc is changed to be DepUnPackPreD.
+
+ Loops are preprocessed and logged. */
+bool pkgOrderList::DepUnPackCrit(DepIterator D)
+{
+ for (; D.end() == false; D++)
+ {
+ if (D.Reverse() == true)
+ {
+ /* Reverse depenanices are only interested in conflicts,
+ predepend breakage is ignored here */
+ if (D->Type != pkgCache::Dep::Conflicts)
+ continue;
+
+ // Duplication elimination, consider only the current version
+ if (D.ParentPkg().CurrentVer() != D.ParentVer())
+ continue;
+
+ /* For reverse dependencies we wish to check if the
+ dependency is satisifed in the install state. The
+ target package (caller) is going to be in the installed
+ state. */
+ if (CheckDep(D) == true)
+ continue;
+
+ if (VisitNode(D.ParentPkg()) == false)
+ return false;
+ }
+ else
+ {
+ /* Forward critical dependencies MUST be correct before the
+ package can be unpacked. */
+ if (D->Type != pkgCache::Dep::Conflicts && D->Type != pkgCache::Dep::PreDepends)
+ continue;
+
+ /* We wish to check if the dep is okay in the now state of the
+ target package against the install state of this package. */
+ if (CheckDep(D) == true)
+ {
+ /* We want to catch predepends loops with the code below.
+ Conflicts loops that are Dep OK are ignored */
+ if (IsFlag(D.TargetPkg(),AddPending) == false ||
+ D->Type != pkgCache::Dep::PreDepends)
+ continue;
+ }
+
+ // This is the loop detection
+ if (IsFlag(D.TargetPkg(),Added) == true ||
+ IsFlag(D.TargetPkg(),AddPending) == true)
+ {
+ if (IsFlag(D.TargetPkg(),AddPending) == true)
+ AddLoop(D);
+ continue;
+ }
+
+ /* Predepends require a special ordering stage, they must have
+ all dependents installed as well */
+ DepFunc Old = Primary;
+ bool Res = false;
+ if (D->Type == pkgCache::Dep::PreDepends)
+ Primary = &DepUnPackPreD;
+ Res = VisitProvides(D);
+ Primary = Old;
+ if (Res == false)
+ return false;
+ }
+ }
+ return true;
+}
+ /*}}}*/
+// OrderList::DepUnPackPreD - Critical UnPacking ordering with depends /*{{{*/
+// ---------------------------------------------------------------------
+/* Critical PreDepends (also configure immediate and essential) strives to
+ ensure not only that all conflicts+predepends are met but that this
+ package will be immediately configurable when it is unpacked.
+
+ Loops are preprocessed and logged. */
+bool pkgOrderList::DepUnPackPreD(DepIterator D)
+{
+ if (D.Reverse() == true)
+ return DepUnPackCrit(D);
+
+ for (; D.end() == false; D++)
+ {
+ if (D.IsCritical() == false)
+ continue;
+
+ /* We wish to check if the dep is okay in the now state of the
+ target package against the install state of this package. */
+ if (CheckDep(D) == true)
+ {
+ /* We want to catch predepends loops with the code below.
+ Conflicts loops that are Dep OK are ignored */
+ if (IsFlag(D.TargetPkg(),AddPending) == false ||
+ D->Type != pkgCache::Dep::PreDepends)
+ continue;
+ }
+
+ // This is the loop detection
+ if (IsFlag(D.TargetPkg(),Added) == true ||
+ IsFlag(D.TargetPkg(),AddPending) == true)
+ {
+ if (IsFlag(D.TargetPkg(),AddPending) == true)
+ AddLoop(D);
+ continue;
+ }
+
+ if (VisitProvides(D) == false)
+ return false;
+ }
+ return true;
+}
+ /*}}}*/
+// OrderList::DepUnPackPre - Critical Predepends ordering /*{{{*/
+// ---------------------------------------------------------------------
+/* Critical PreDepends (also configure immediate and essential) strives to
+ ensure not only that all conflicts+predepends are met but that this
+ package will be immediately configurable when it is unpacked.
+
+ Loops are preprocessed and logged. All loops will be fatal. */
+bool pkgOrderList::DepUnPackPre(DepIterator D)
+{
+ if (D.Reverse() == true)
+ return true;
+
+ for (; D.end() == false; D++)
+ {
+ /* Only consider the PreDepends or Depends. Depends are only
+ considered at the lowest depth or in the case of immediate
+ configure */
+ if (D->Type != pkgCache::Dep::PreDepends)
+ {
+ if (D->Type == pkgCache::Dep::Depends)
+ {
+ if (Depth == 1 && IsFlag(D.ParentPkg(),Immediate) == false)
+ continue;
+ }
+ else
+ continue;
+ }
+
+ /* We wish to check if the dep is okay in the now state of the
+ target package against the install state of this package. */
+ if (CheckDep(D) == true)
+ {
+ /* We want to catch predepends loops with the code below.
+ Conflicts loops that are Dep OK are ignored */
+ if (IsFlag(D.TargetPkg(),AddPending) == false)
+ continue;
+ }
+
+ // This is the loop detection
+ if (IsFlag(D.TargetPkg(),Added) == true ||
+ IsFlag(D.TargetPkg(),AddPending) == true)
+ {
+ if (IsFlag(D.TargetPkg(),AddPending) == true)
+ AddLoop(D);
+ continue;
+ }
+
+ if (VisitProvides(D) == false)
+ return false;
+ }
+ return true;
+}
+ /*}}}*/
+// OrderList::DepUnPackDep - Reverse dependency considerations /*{{{*/
+// ---------------------------------------------------------------------
+/* Reverse dependencies are considered to determine if unpacking this
+ package will break any existing dependencies. If so then those
+ packages are ordered before this one so that they are in the
+ UnPacked state.
+
+ The forwards depends loop is designed to bring the packages dependents
+ close to the package. This helps reduce deconfigure time.
+
+ Loops are irrelevent to this. */
+bool pkgOrderList::DepUnPackDep(DepIterator D)
+{
+
+ for (; D.end() == false; D++)
+ if (D.IsCritical() == true)
+ {
+ if (D.Reverse() == true)
+ {
+ /* Duplication prevention. We consider rev deps only on
+ the current version, a not installed package
+ cannot break */
+ if (D.ParentPkg()->CurrentVer == 0 ||
+ D.ParentPkg().CurrentVer() != D.ParentVer())
+ continue;
+
+ // The dep will not break so it is irrelevent.
+ if (CheckDep(D) == true)
+ continue;
+
+ if (VisitNode(D.ParentPkg()) == false)
+ return false;
+ }
+ else
+ if (D->Type == pkgCache::Dep::Depends)
+ if (VisitProvides(D) == false)
+ return false;
+ }
+ return true;
+}
+ /*}}}*/
+// OrderList::DepConfigure - Configuration ordering /*{{{*/
+// ---------------------------------------------------------------------
+/* Configuration only ordering orders by the Depends: line only. It
+ orders configuration so that when a package comes to be configured it's
+ dependents are configured.
+
+ Loops are ingored. Depends loop entry points are chaotic. */
+bool pkgOrderList::DepConfigure(DepIterator D)
+{
+ // Never consider reverse configuration dependencies.
+ if (D.Reverse() == true)
+ return true;
+
+ for (; D.end() == false; D++)
+ if (D->Type == pkgCache::Dep::Depends)
+ if (VisitProvides(D) == false)
+ return false;
+ return true;
+}
+ /*}}}*/
+// OrderList::DepRemove - Removal ordering /*{{{*/
+// ---------------------------------------------------------------------
+/* Removal visits all reverse depends. It considers if the dependency
+ of the Now state version to see if it is okay with removing this
+ package. This check should always fail, but is provided for symetery
+ with the other critical handlers.
+
+ Loops are preprocessed and logged. Removal loops can also be
+ detected in the critical handler. They are characterized by an
+ old version of A depending on B but the new version of A conflicting
+ with B, thus either A or B must break to install. */
+bool pkgOrderList::DepRemove(DepIterator D)
+{
+ if (D.Reverse() == false)
+ return true;
+ for (; D.end() == false; D++)
+ if (D->Type == pkgCache::Dep::Depends || D->Type == pkgCache::Dep::PreDepends)
+ {
+ // Duplication elimination, consider the current version only
+ if (D.ParentPkg().CurrentVer() != D.ParentVer())
+ continue;
+
+ /* We wish to see if the dep on the parent package is okay
+ in the removed (install) state of the target pkg. */
+ if (CheckDep(D) == true)
+ {
+ // We want to catch loops with the code below.
+ if (IsFlag(D.ParentPkg(),AddPending) == false)
+ continue;
+ }
+
+ // This is the loop detection
+ if (IsFlag(D.ParentPkg(),Added) == true ||
+ IsFlag(D.ParentPkg(),AddPending) == true)
+ {
+ if (IsFlag(D.ParentPkg(),AddPending) == true)
+ AddLoop(D);
+ continue;
+ }
+
+ if (VisitNode(D.ParentPkg()) == false)
+ return false;
+ }
+
+ return true;
+}
+ /*}}}*/
+
+// OrderList::AddLoop - Add a loop to the loop list /*{{{*/
+// ---------------------------------------------------------------------
+/* We record the loops. This is a relic since loop breaking is done
+ genericaly as part of the safety routines. */
+bool pkgOrderList::AddLoop(DepIterator D)
+{
+ if (LoopCount < 0 || LoopCount >= 20)
+ return false;
+
+ // Skip dups
+ if (LoopCount != 0)
+ {
+ if (Loops[LoopCount - 1].ParentPkg() == D.ParentPkg() ||
+ Loops[LoopCount - 1].TargetPkg() == D.ParentPkg())
+ return true;
+ }
+
+ Loops[LoopCount++] = D;
+
+ // Mark the packages as being part of a loop.
+ Flag(D.TargetPkg(),Loop);
+ Flag(D.ParentPkg(),Loop);
+ return true;
+}
+ /*}}}*/
+// OrderList::WipeFlags - Unset the given flags from all packages /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+void pkgOrderList::WipeFlags(unsigned long F)
+{
+ unsigned long Size = Cache.HeaderP->PackageCount;
+ for (unsigned long I = 0; I != Size; I++)
+ Flags[I] &= ~F;
+}
+ /*}}}*/
+// OrderList::CheckDep - Check a dependency for truth /*{{{*/
+// ---------------------------------------------------------------------
+/* This performs a complete analysis of the dependency wrt to the
+ current add list. It returns true if after all events are
+ performed it is still true. This sort of routine can be approximated
+ by examining the DepCache, however in convoluted cases of provides
+ this fails to produce a suitable result. */
+bool pkgOrderList::CheckDep(DepIterator D)
+{
+ Version **List = D.AllTargets();
+ for (Version **I = List; *I != 0; I++)
+ {
+ VerIterator Ver(Cache,*I);
+ PkgIterator Pkg = Ver.ParentPkg();
+
+ /* The meaning of Added and AddPending is subtle. AddPending is
+ an indication that the package is looping. Because of the
+ way ordering works Added means the package will be unpacked
+ before this one and AddPending means after. It is therefore
+ correct to ignore AddPending in all cases, but that exposes
+ reverse-ordering loops which should be ignore. */
+ if (IsFlag(Pkg,Added) == true ||
+ (IsFlag(Pkg,AddPending) == true && D.Reverse() == true))
+ {
+ if (Cache[Pkg].InstallVer != *I)
+ continue;
+ }
+ else
+ if ((Version *)Pkg.CurrentVer() != *I ||
+ Pkg.State() != PkgIterator::NeedsNothing)
+ continue;
+
+ delete [] List;
+
+ /* Conflicts requires that all versions are not present, depends
+ just needs one */
+ if (D->Type != pkgCache::Dep::Conflicts)
+ return true;
+ else
+ return false;
+ }
+ delete [] List;
+
+ /* Conflicts requires that all versions are not present, depends
+ just needs one */
+ if (D->Type == pkgCache::Dep::Conflicts)
+ return true;
+ return false;
+}
+ /*}}}*/
diff --git a/apt-pkg/orderlist.h b/apt-pkg/orderlist.h
new file mode 100644
index 000000000..0dc8a5038
--- /dev/null
+++ b/apt-pkg/orderlist.h
@@ -0,0 +1,123 @@
+// -*- mode: cpp; mode: fold -*-
+// Description /*{{{*/
+// $Id: orderlist.h,v 1.1 1998/07/07 04:17:01 jgg Exp $
+/* ######################################################################
+
+ Order List - Represents and Manipulates an ordered list of packages.
+
+ A list of packages can be ordered by a number of conflicting criteria
+ each given a specific priority. Each package also has a set of flags
+ indicating some usefull things about it that are derived in the
+ course of sorting. The pkgPackageManager class uses this class for
+ all of it's installation ordering needs.
+
+ ##################################################################### */
+ /*}}}*/
+// Header section: pkglib
+#ifndef PKGLIB_ORDERLIST_H
+#define PKGLIB_ORDERLIST_H
+
+#ifdef __GNUG__
+#pragma interface "pkglib/orderlist.h"
+#endif
+
+#include <pkglib/pkgcache.h>
+
+class pkgDepCache;
+class pkgOrderList
+{
+ protected:
+
+ pkgDepCache &Cache;
+
+ // Bring some usefull types into the local scope
+ typedef pkgCache::PkgIterator PkgIterator;
+ typedef pkgCache::VerIterator VerIterator;
+ typedef pkgCache::DepIterator DepIterator;
+ typedef pkgCache::PrvIterator PrvIterator;
+ typedef pkgCache::Package Package;
+ typedef pkgCache::Version Version;
+ typedef bool (pkgOrderList::*DepFunc)(DepIterator D);
+
+ // These are the currently selected ordering functions
+ DepFunc Primary;
+ DepFunc Secondary;
+ DepFunc RevDepends;
+ DepFunc Remove;
+
+ // State
+ Package **End;
+ Package **List;
+ DepIterator Loops[20];
+ int LoopCount;
+ int Depth;
+ unsigned char *Flags;
+
+ // Main visit function
+ bool VisitNode(PkgIterator Pkg);
+ bool VisitDeps(DepFunc F,PkgIterator Pkg);
+ bool VisitRDeps(DepFunc F,PkgIterator Pkg);
+ bool VisitRProvides(DepFunc F,VerIterator Ver);
+ bool VisitProvides(DepIterator Pkg);
+
+ // Dependency checking functions.
+ bool DepUnPackCrit(DepIterator D);
+ bool DepUnPackPreD(DepIterator D);
+ bool DepUnPackPre(DepIterator D);
+ bool DepUnPackDep(DepIterator D);
+ bool DepConfigure(DepIterator D);
+ bool DepRemove(DepIterator D);
+
+ // Analysis helpers
+ bool AddLoop(DepIterator D);
+ bool CheckDep(DepIterator D);
+ bool DoRun();
+
+ // For pre sorting
+ static pkgOrderList *Me;
+ static int OrderCompareA(const void *a, const void *b);
+ static int OrderCompareB(const void *a, const void *b);
+ int FileCmp(PkgIterator A,PkgIterator B);
+
+ public:
+
+ typedef Package **iterator;
+
+ // State flags
+ enum Flags {Added = (1 << 0), AddPending = (1 << 1),
+ Immediate = (1 << 2), Loop = (1 << 3),
+ UnPacked = (1 << 4), Configured = (1 << 5),
+ Removed = (1 << 6),
+ InList = (1 << 7),
+ States = (UnPacked | Configured | Removed)};
+
+ // Flag manipulators
+ inline bool IsFlag(PkgIterator Pkg,unsigned long F) {return (Flags[Pkg->ID] & F) == F;};
+ inline bool IsFlag(Package *Pkg,unsigned long F) {return (Flags[Pkg->ID] & F) == F;};
+ void Flag(PkgIterator Pkg,unsigned long State, unsigned long F) {Flags[Pkg->ID] = (Flags[Pkg->ID] & (~F)) | State;};
+ inline void Flag(PkgIterator Pkg,unsigned long F) {Flags[Pkg->ID] |= F;};
+ inline void Flag(Package *Pkg,unsigned long F) {Flags[Pkg->ID] |= F;};
+ inline bool IsNow(PkgIterator Pkg) {return (Flags[Pkg->ID] & States) == 0;};
+ void WipeFlags(unsigned long F);
+
+ // Accessors
+ inline iterator begin() {return List;};
+ inline iterator end() {return End;};
+ inline void push_back(Package *Pkg) {*(End++) = Pkg;};
+ inline void push_back(PkgIterator Pkg) {*(End++) = Pkg;};
+ inline void pop_back() {End--;};
+ inline bool empty() {return End == List;};
+ inline unsigned int size() {return End - List;};
+
+ // Ordering modes
+ bool OrderCritical();
+ bool OrderUnpack();
+ bool OrderConfigure();
+
+ int Score(PkgIterator Pkg);
+
+ pkgOrderList(pkgDepCache &Cache);
+ ~pkgOrderList();
+};
+
+#endif
diff --git a/apt-pkg/packagemanager.cc b/apt-pkg/packagemanager.cc
new file mode 100644
index 000000000..ebf67b5ee
--- /dev/null
+++ b/apt-pkg/packagemanager.cc
@@ -0,0 +1,548 @@
+// -*- mode: cpp; mode: fold -*-
+// Description /*{{{*/
+// $Id: packagemanager.cc,v 1.1 1998/07/07 04:17:01 jgg Exp $
+/* ######################################################################
+
+ Package Manager - Abstacts the package manager
+
+ More work is needed in the area of transitioning provides, ie exim
+ replacing smail. This can cause interesing side effects.
+
+ Other cases involving conflicts+replaces should be tested.
+
+ ##################################################################### */
+ /*}}}*/
+// Include Files /*{{{*/
+#ifdef __GNUG__
+#pragma implementation "pkglib/packagemanager.h"
+#endif
+#include <pkglib/packagemanager.h>
+#include <pkglib/orderlist.h>
+#include <pkglib/depcache.h>
+#include <pkglib/sourcelist.h>
+#include <pkglib/aquire.h>
+#include <pkglib/controlcache.h>
+#include <pkglib/error.h>
+#include <options.h>
+ /*}}}*/
+
+// PM::PackageManager - Constructor /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+pkgPackageManager::pkgPackageManager(pkgDepCache &Cache) : Cache(Cache)
+{
+ FileNames = new string[Cache.Head().PackageCount];
+ List = 0;
+}
+ /*}}}*/
+// PM::PackageManager - Destructor /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+pkgPackageManager::~pkgPackageManager()
+{
+ delete List;
+ delete [] FileNames;
+}
+ /*}}}*/
+// PM::GetArchives - Puts the install archives in the aquire list /*{{{*/
+// ---------------------------------------------------------------------
+/* The Source list is used to convert the packages to install into
+ URNs which are then passed to Aquire to convert to FileNames. */
+bool pkgPackageManager::GetArchives(pkgSourceList &List,pkgAquire &Engine)
+{
+ pkgControlCache CCache(Cache);
+ if (_error->PendingError() == true)
+ return false;
+
+ Engine.OutputDir(PKG_DEB_CA_ARCHIVES);
+ pkgCache::PkgIterator I = Cache.PkgBegin();
+ for (;I.end() != true; I++)
+ {
+ // Not interesting
+ if ((Cache[I].InstallVer == (pkgCache::Version *)I.CurrentVer() &&
+ I.State() != pkgCache::PkgIterator::NeedsUnpack) ||
+ Cache[I].Delete() == true)
+ continue;
+
+ // Cross match with the source list.
+ pkgSourceList::const_iterator Dist = List.MatchPkgFile(Cache[I].InstVerIter(Cache));
+ if (Dist == List.end())
+ {
+ _error->Warning("Couldn't locate an archive source for package %s",I.Name());
+ continue;
+ }
+
+ // Read in the info record
+ pkgSPkgCtrlInfo Inf = CCache[Cache[I].InstVerIter(Cache)];
+ if (Inf.isNull() == true)
+ {
+ _error->Warning("Couldn't locate info for package %s",I.Name());
+ continue;
+ }
+
+ // Isolate the filename
+ string File = Inf->Find("Filename")->Value();
+ if (File.empty() == true)
+ {
+ _error->Warning("Couldn't locate an archive for package %s",I.Name());
+ continue;
+ }
+
+ // Generate the get request.
+ string URI = Dist->ArchiveURI(File);
+
+ // Output file
+ unsigned int Pos = File.rfind('/');
+ if (Pos == File.length())
+ return _error->Error("Malformed file line in package %s",I.Name());
+
+ // Null pos isnt used in present package files
+ if (Pos == string::npos)
+ Pos = 0;
+ else
+ Pos++;
+
+ if (Engine.Get(URI,string(File,Pos),
+ Dist->ArchiveInfo(Cache[I].InstVerIter(Cache)),
+ Cache[I].InstVerIter(Cache)->Size,
+ Inf->Find("MD5sum")->Value(),
+ &FileNames[I->ID]) == false)
+ return false;
+ }
+
+ return true;
+}
+ /*}}}*/
+// PM::FixMissing - Keep all missing packages /*{{{*/
+// ---------------------------------------------------------------------
+/* This is called to correct the installation when packages could not
+ be downloaded. */
+bool pkgPackageManager::FixMissing()
+{
+ unsigned char *Touch = new unsigned char[Cache.Head().PackageCount];
+ for (PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+ {
+ // Create the status list that ResolveConflicts needs
+ if ((Cache[I].DepState & pkgDepCache::DepNowMin) == pkgDepCache::DepNowMin)
+ Touch[I->ID] = (1 << 0) | (1 << 1);
+ else
+ Touch[I->ID] = 1 << 1;
+
+ if (Cache[I].Keep() == true)
+ continue;
+ if (FileNames[I->ID].empty() == false || Cache[I].Delete() == true)
+ continue;
+ Cache.MarkKeep(I);
+ }
+
+ // Now downgrade everything that is broken
+ Cache.ResolveConflicts(Touch);
+ delete [] Touch;
+
+ return Cache.BrokenCount() == 0;
+}
+ /*}}}*/
+
+// PM::DepAlwaysTrue - Returns true if this dep is irrelevent /*{{{*/
+// ---------------------------------------------------------------------
+/* The restriction on provides is to eliminate the case when provides
+ are transitioning between valid states [ie exim to smail] */
+bool pkgPackageManager::DepAlwaysTrue(DepIterator D)
+{
+ if (D.TargetPkg()->ProvidesList != 0)
+ return false;
+
+ if ((Cache[D] & pkgDepCache::DepInstall) != 0 &&
+ (Cache[D] & pkgDepCache::DepNow) != 0)
+ return true;
+ return false;
+}
+ /*}}}*/
+// PM::CheckRConflicts - Look for reverse conflicts /*{{{*/
+// ---------------------------------------------------------------------
+/* This looks over the reverses for a conflicts line that needs early
+ removal. */
+bool pkgPackageManager::CheckRConflicts(PkgIterator Pkg,DepIterator D,
+ const char *Ver)
+{
+ for (;D.end() == false; D++)
+ {
+ if (D->Type != pkgDEP_Conflicts)
+ continue;
+
+ if (D.ParentPkg() == Pkg)
+ continue;
+
+ if (pkgCheckDep(D.TargetVer(),Ver,D->CompareOp) == false)
+ continue;
+
+ if (List->IsNow(Pkg) == false)
+ continue;
+
+ if (EarlyRemove(D.ParentPkg()) == false)
+ return false;
+ }
+ return true;
+}
+ /*}}}*/
+// PM::ConfigureAll - Run the all out configuration /*{{{*/
+// ---------------------------------------------------------------------
+/* This configures every package. It is assumed they are all unpacked and
+ that the final configuration is valid. */
+bool pkgPackageManager::ConfigureAll()
+{
+ pkgOrderList OList(Cache);
+
+ // Populate the order list
+ for (pkgOrderList::iterator I = List->begin(); I != List->end(); I++)
+ if (List->IsFlag(pkgCache::PkgIterator(Cache,*I),
+ pkgOrderList::UnPacked) == true)
+ OList.push_back(*I);
+
+ if (OList.OrderConfigure() == false)
+ return false;
+
+ // Perform the configuring
+ for (pkgOrderList::iterator I = OList.begin(); I != OList.end(); I++)
+ {
+ PkgIterator Pkg(Cache,*I);
+
+ if (Configure(Pkg) == false)
+ return false;
+
+ List->Flag(Pkg,pkgOrderList::Configured,pkgOrderList::States);
+ }
+
+ return true;
+}
+ /*}}}*/
+// PM::SmartConfigure - Perform immediate configuration of the pkg /*{{{*/
+// ---------------------------------------------------------------------
+/* This routine scheduals the configuration of the given package and all
+ of it's dependents. */
+bool pkgPackageManager::SmartConfigure(PkgIterator Pkg)
+{
+ pkgOrderList OList(Cache);
+
+ if (DepAdd(OList,Pkg) == false)
+ return false;
+
+ if (OList.OrderConfigure() == false)
+ return false;
+
+ // Perform the configuring
+ for (pkgOrderList::iterator I = OList.begin(); I != OList.end(); I++)
+ {
+ PkgIterator Pkg(Cache,*I);
+
+ if (Configure(Pkg) == false)
+ return false;
+
+ List->Flag(Pkg,pkgOrderList::Configured,pkgOrderList::States);
+ }
+
+ // Sanity Check
+ if (List->IsFlag(Pkg,pkgOrderList::Configured) == false)
+ return _error->Error("Internal error, could not immediate configure %s",Pkg.Name());
+
+ return true;
+}
+ /*}}}*/
+// PM::DepAdd - Add all dependents to the oder list /*{{{*/
+// ---------------------------------------------------------------------
+/* This recursively adds all dependents to the order list */
+bool pkgPackageManager::DepAdd(pkgOrderList &OList,PkgIterator Pkg,int Depth)
+{
+ if (OList.IsFlag(Pkg,pkgOrderList::Added) == true)
+ return true;
+ if (List->IsFlag(Pkg,pkgOrderList::Configured) == true)
+ return true;
+ if (List->IsFlag(Pkg,pkgOrderList::UnPacked) == false)
+ return false;
+
+
+ // Put the package on the list
+ OList.push_back(Pkg);
+ OList.Flag(Pkg,pkgOrderList::Added);
+ Depth++;
+
+ // Check the dependencies to see if they are all satisfied.
+ bool Bad = false;
+ for (DepIterator D = Cache[Pkg].InstVerIter(Cache).DependsList(); D.end() == false;)
+ {
+ if (D->Type != pkgDEP_Depends && D->Type != pkgDEP_PreDepends)
+ {
+ D++;
+ continue;
+ }
+
+ // Grok or groups
+ Bad = true;
+ for (bool LastOR = true; D.end() == false && LastOR == true; D++)
+ {
+ LastOR = (D->CompareOp & pkgOP_OR) == pkgOP_OR;
+
+ if (Bad == false)
+ continue;
+
+ Version **VList = D.AllTargets();
+ for (Version **I = VList; *I != 0 && Bad == true; I++)
+ {
+ VerIterator Ver(Cache,*I);
+ PkgIterator Pkg = Ver.ParentPkg();
+
+ // See if the current version is ok
+ if (Pkg.CurrentVer() == Ver && List->IsNow(Pkg) == true &&
+ Pkg.State() == PkgIterator::NeedsNothing)
+ {
+ Bad = false;
+ continue;
+ }
+
+ // Not the install version
+ if (Cache[Pkg].InstallVer != *I ||
+ (Cache[Pkg].Keep() == true && Pkg.State() == PkgIterator::NeedsNothing))
+ continue;
+ if (List->IsFlag(Pkg,pkgOrderList::UnPacked) == true)
+ Bad = !DepAdd(OList,Pkg,Depth);
+ if (List->IsFlag(Pkg,pkgOrderList::Configured) == true)
+ Bad = false;
+ }
+ delete [] VList;
+ }
+
+ if (Bad == true)
+ {
+ OList.Flag(Pkg,0,pkgOrderList::Added);
+ OList.pop_back();
+ Depth--;
+ return false;
+ }
+ }
+
+ Depth--;
+ return true;
+}
+ /*}}}*/
+// PM::EarlyRemove - Perform removal of packages before their time /*{{{*/
+// ---------------------------------------------------------------------
+/* This is called to deal with conflicts arising from unpacking */
+bool pkgPackageManager::EarlyRemove(PkgIterator Pkg)
+{
+ if (List->IsNow(Pkg) == false)
+ return true;
+
+ // Already removed it
+ if (List->IsFlag(Pkg,pkgOrderList::Removed) == true)
+ return true;
+
+ // Woops, it will not be re-installed!
+ if (List->IsFlag(Pkg,pkgOrderList::InList) == false)
+ return false;
+
+ bool Res = SmartRemove(Pkg);
+ if (Cache[Pkg].Delete() == false)
+ List->Flag(Pkg,pkgOrderList::Removed,pkgOrderList::States);
+
+ return Res;
+}
+ /*}}}*/
+// PM::SmartRemove - Removal Helper /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool pkgPackageManager::SmartRemove(PkgIterator Pkg)
+{
+ if (List->IsNow(Pkg) == false)
+ return true;
+
+ List->Flag(Pkg,pkgOrderList::Configured,pkgOrderList::States);
+ return Remove(Pkg);
+}
+ /*}}}*/
+// PM::SmartUnPack - Install helper /*{{{*/
+// ---------------------------------------------------------------------
+/* This performs the task of handling pre-depends. */
+bool pkgPackageManager::SmartUnPack(PkgIterator Pkg)
+{
+ // Check if it is already unpacked
+ if (Pkg.State() == pkgCache::PkgIterator::NeedsConfigure &&
+ Cache[Pkg].Keep() == true)
+ {
+ List->Flag(Pkg,pkgOrderList::UnPacked,pkgOrderList::States);
+ if (List->IsFlag(Pkg,pkgOrderList::Immediate) == true)
+ if (SmartConfigure(Pkg) == false)
+ return _error->Error("Internal Error, Could not perform immediate configuraton");
+ return true;
+ }
+
+ /* See if this packages install version has any predependencies
+ that are not met by 'now' packages. */
+ for (DepIterator D = Cache[Pkg].InstVerIter(Cache).DependsList();
+ D.end() == false; D++)
+ {
+ if (D->Type == pkgDEP_PreDepends)
+ {
+ // Look for possible ok targets.
+ Version **VList = D.AllTargets();
+ bool Bad = true;
+ for (Version **I = VList; *I != 0 && Bad == true; I++)
+ {
+ VerIterator Ver(Cache,*I);
+ PkgIterator Pkg = Ver.ParentPkg();
+
+ // See if the current version is ok
+ if (Pkg.CurrentVer() == Ver && List->IsNow(Pkg) == true &&
+ Pkg.State() == PkgIterator::NeedsNothing)
+ {
+ Bad = false;
+ continue;
+ }
+ }
+
+ // Look for something that could be configured.
+ for (Version **I = VList; *I != 0 && Bad == true; I++)
+ {
+ VerIterator Ver(Cache,*I);
+ PkgIterator Pkg = Ver.ParentPkg();
+
+ // Not the install version
+ if (Cache[Pkg].InstallVer != *I ||
+ (Cache[Pkg].Keep() == true && Pkg.State() == PkgIterator::NeedsNothing))
+ continue;
+
+ Bad = !SmartConfigure(Pkg);
+ }
+
+ delete [] VList;
+
+ if (Bad == true)
+ return _error->Error("Internal Error, Couldn't configure a pre-depend");
+
+ continue;
+ }
+
+ if (D->Type == pkgDEP_Conflicts)
+ {
+ /* Look for conflicts. Two packages that are both in the install
+ state cannot conflict so we don't check.. */
+ Version **VList = D.AllTargets();
+ for (Version **I = VList; *I != 0; I++)
+ {
+ VerIterator Ver(Cache,*I);
+ PkgIterator Pkg = Ver.ParentPkg();
+
+ // See if the current version is conflicting
+ if (Pkg.CurrentVer() == Ver && List->IsNow(Pkg) == true)
+ {
+ if (EarlyRemove(Pkg) == false)
+ return _error->Error("Internal Error, Could not early remove %s",Pkg.Name());
+ }
+ }
+ delete [] VList;
+ }
+ }
+
+ // Check for reverse conflicts.
+ CheckRConflicts(Pkg,Pkg.RevDependsList(),
+ Cache[Pkg].InstVerIter(Cache).VerStr());
+ for (PrvIterator P = Cache[Pkg].InstVerIter(Cache).ProvidesList();
+ P.end() == false; P++)
+ CheckRConflicts(Pkg,P.ParentPkg().RevDependsList(),P.ProvideVersion());
+
+ if (Install(Pkg,FileNames[Pkg->ID]) == false)
+ return false;
+
+ List->Flag(Pkg,pkgOrderList::UnPacked,pkgOrderList::States);
+
+ // Perform immedate configuration of the package.
+ if (List->IsFlag(Pkg,pkgOrderList::Immediate) == true)
+ if (SmartConfigure(Pkg) == false)
+ return _error->Error("Internal Error, Could not perform immediate configuraton");
+
+ return true;
+}
+ /*}}}*/
+// PM::OrderInstall - Installation ordering routine /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool pkgPackageManager::OrderInstall()
+{
+ delete List;
+ List = new pkgOrderList(Cache);
+
+ // Generate the list of affected packages and sort it
+ for (PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+ {
+ // Consider all depends
+ if ((I->Flags & pkgFLAG_Essential) == pkgFLAG_Essential)
+ {
+ List->Flag(I,pkgOrderList::Immediate);
+ if (Cache[I].InstallVer != 0)
+ for (DepIterator D = Cache[I].InstVerIter(Cache).DependsList();
+ D.end() == false; D++)
+ if (D->Type == pkgDEP_Depends || D->Type == pkgDEP_PreDepends)
+ List->Flag(D.TargetPkg(),pkgOrderList::Immediate);
+ if (I->CurrentVer != 0)
+ for (DepIterator D = I.CurrentVer().DependsList();
+ D.end() == false; D++)
+ if (D->Type == pkgDEP_Depends || D->Type == pkgDEP_PreDepends)
+ List->Flag(D.TargetPkg(),pkgOrderList::Immediate);
+ }
+
+ // Not interesting
+ if ((Cache[I].Keep() == true ||
+ Cache[I].InstVerIter(Cache) == I.CurrentVer()) &&
+ I.State() == pkgCache::PkgIterator::NeedsNothing)
+ continue;
+
+ // Append it to the list
+ List->push_back(I);
+
+ if ((I->Flags & pkgFLAG_ImmediateConf) == pkgFLAG_ImmediateConf)
+ List->Flag(I,pkgOrderList::Immediate);
+ }
+
+ if (List->OrderUnpack() == false)
+ return _error->Error("Internal ordering error");
+
+ for (pkgOrderList::iterator I = List->begin(); I != List->end(); I++)
+ {
+ PkgIterator Pkg(Cache,*I);
+
+ // Sanity check
+ if (Cache[Pkg].Keep() == true && Pkg.State() == pkgCache::PkgIterator::NeedsNothing)
+ return _error->Error("Internal Error, trying to manipulate a kept package");
+
+ // Perform a delete or an install
+ if (Cache[Pkg].Delete() == true)
+ {
+ if (SmartRemove(Pkg) == false)
+ return false;
+ }
+ else
+ if (SmartUnPack(Pkg) == false)
+ return false;
+ }
+
+ // Final run through the configure phase
+ if (ConfigureAll() == false)
+ return false;
+
+ // Sanity check
+ for (pkgOrderList::iterator I = List->begin(); I != List->end(); I++)
+ if (List->IsFlag(*I,pkgOrderList::Configured) == false)
+ return _error->Error("Internal error, packages left unconfigured. %s",
+ PkgIterator(Cache,*I).Name());
+
+ return true;
+}
+ /*}}}*/
+// PM::DoInstall - Does the installation /*{{{*/
+// ---------------------------------------------------------------------
+/* This uses the filenames in FileNames and the information in the
+ DepCache to perform the installation of packages.*/
+bool pkgPackageManager::DoInstall()
+{
+ return OrderInstall() && Go();
+}
+ /*}}}*/
diff --git a/apt-pkg/packagemanager.h b/apt-pkg/packagemanager.h
new file mode 100644
index 000000000..6020cbefd
--- /dev/null
+++ b/apt-pkg/packagemanager.h
@@ -0,0 +1,84 @@
+// -*- mode: cpp; mode: fold -*-
+// Description /*{{{*/
+// $Id: packagemanager.h,v 1.1 1998/07/07 04:17:01 jgg Exp $
+/* ######################################################################
+
+ Package Manager - Abstacts the package manager
+
+ Three steps are
+ - Aquiration of archives (stores the list of final file names)
+ - Sorting of operations
+ - Inokation of package manager
+
+ This is the final stage when the package cache entities get converted
+ into file names and the state stored in a DepCache is transformed
+ into a series of operations.
+
+ In the final scheme of things this may serve as a director class to
+ access the actual install methods based on the file type being
+ installed.
+
+ ##################################################################### */
+ /*}}}*/
+// Header section: pkglib
+#ifndef PKGLIB_PACKAGEMANAGER_H
+#define PKGLIB_PACKAGEMANAGER_H
+
+#ifdef __GNUG__
+#pragma interface "pkglib/packagemanager.h"
+#endif
+
+#include <string>
+#include <pkglib/pkgcache.h>
+
+class pkgAquire;
+class pkgDepCache;
+class pkgSourceList;
+class pkgOrderList;
+class pkgPackageManager
+{
+ protected:
+ string *FileNames;
+ pkgDepCache &Cache;
+ pkgOrderList *List;
+
+ // Bring some usefull types into the local scope
+ typedef pkgCache::PkgIterator PkgIterator;
+ typedef pkgCache::VerIterator VerIterator;
+ typedef pkgCache::DepIterator DepIterator;
+ typedef pkgCache::PrvIterator PrvIterator;
+ typedef pkgCache::Version Version;
+ typedef pkgCache::Package Package;
+
+ bool DepAdd(pkgOrderList &Order,PkgIterator P,int Depth = 0);
+ bool OrderInstall();
+ bool CheckRConflicts(PkgIterator Pkg,DepIterator Dep,const char *Ver);
+
+ // Analysis helpers
+ bool DepAlwaysTrue(DepIterator D);
+
+ // Install helpers
+ bool ConfigureAll();
+ bool SmartConfigure(PkgIterator Pkg);
+ bool SmartUnPack(PkgIterator Pkg);
+ bool SmartRemove(PkgIterator Pkg);
+ bool EarlyRemove(PkgIterator Pkg);
+
+ // The Actuall installation implementation
+ virtual bool Install(PkgIterator /*Pkg*/,string /*File*/) {return false;};
+ virtual bool Configure(PkgIterator /*Pkg*/) {return false;};
+ virtual bool Remove(PkgIterator /*Pkg*/) {return false;};
+ virtual bool Go() {return false;};
+
+ public:
+
+ // The three stages
+ bool GetArchives(pkgSourceList &List,pkgAquire &Engine);
+ bool DoInstall();
+ bool FixMissing();
+
+ pkgPackageManager(pkgDepCache &Cache);
+ virtual ~pkgPackageManager();
+};
+
+#endif
diff --git a/apt-pkg/pkgcache.cc b/apt-pkg/pkgcache.cc
index b9dbf34ec..085225031 100644
--- a/apt-pkg/pkgcache.cc
+++ b/apt-pkg/pkgcache.cc
@@ -1,6 +1,6 @@
// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: pkgcache.cc,v 1.4 1998/07/05 05:33:53 jgg Exp $
+// $Id: pkgcache.cc,v 1.5 1998/07/07 04:17:02 jgg Exp $
/* ######################################################################
Package Cache - Accessor code for the cache
@@ -20,6 +20,10 @@
##################################################################### */
/*}}}*/
// Include Files /*{{{*/
+#ifdef __GNUG__
+#pragma implementation "pkglib/pkgcache.h"
+#pragma implementation "pkglib/cacheiterators.h"
+#endif
#include <pkglib/pkgcache.h>
#include <pkglib/version.h>
#include <pkglib/error.h>
@@ -199,13 +203,13 @@ void pkgCache::PkgIterator::operator ++(int)
/* By this we mean if it is either cleanly installed or cleanly removed. */
pkgCache::PkgIterator::OkState pkgCache::PkgIterator::State() const
{
- if (Pkg->CurrentState == UnPacked ||
- Pkg->CurrentState == HalfConfigured)
+ if (Pkg->CurrentState == State::UnPacked ||
+ Pkg->CurrentState == State::HalfConfigured)
return NeedsConfigure;
- if (Pkg->CurrentState == UnInstalled ||
- Pkg->CurrentState == HalfInstalled ||
- Pkg->InstState != Ok)
+ if (Pkg->CurrentState == State::UnInstalled ||
+ Pkg->CurrentState == State::HalfInstalled ||
+ Pkg->InstState != State::Ok)
return NeedsUnpack;
return NeedsNothing;
@@ -217,8 +221,8 @@ pkgCache::PkgIterator::OkState pkgCache::PkgIterator::State() const
conflicts. */
bool pkgCache::DepIterator::IsCritical()
{
- if (Dep->Type == Conflicts || Dep->Type == Depends ||
- Dep->Type == PreDepends)
+ if (Dep->Type == Dep::Conflicts || Dep->Type == Dep::Depends ||
+ Dep->Type == Dep::PreDepends)
return true;
return false;
}
@@ -293,7 +297,7 @@ pkgCache::Version **pkgCache::DepIterator::AllTargets()
if (pkgCheckDep(TargetVer(),I.VerStr(),Dep->CompareOp) == false)
continue;
- if (Dep->Type == Conflicts && ParentPkg() == I.ParentPkg())
+ if (Dep->Type == Dep::Conflicts && ParentPkg() == I.ParentPkg())
continue;
Size++;
@@ -307,7 +311,7 @@ pkgCache::Version **pkgCache::DepIterator::AllTargets()
if (pkgCheckDep(TargetVer(),I.ProvideVersion(),Dep->CompareOp) == false)
continue;
- if (Dep->Type == Conflicts && ParentPkg() == I.OwnerPkg())
+ if (Dep->Type == Dep::Conflicts && ParentPkg() == I.OwnerPkg())
continue;
Size++;
diff --git a/apt-pkg/pkgcache.h b/apt-pkg/pkgcache.h
index 836418c2c..852949b1f 100644
--- a/apt-pkg/pkgcache.h
+++ b/apt-pkg/pkgcache.h
@@ -1,6 +1,6 @@
// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: pkgcache.h,v 1.4 1998/07/05 05:33:55 jgg Exp $
+// $Id: pkgcache.h,v 1.5 1998/07/07 04:17:03 jgg Exp $
/* ######################################################################
Cache - Structure definitions for the cache file
@@ -20,6 +20,10 @@
#ifndef PKGLIB_PKGCACHE_H
#define PKGLIB_PKGCACHE_H
+#ifdef __GNUG__
+#pragma interface "pkglib/pkgcache.h"
+#endif
+
#include <string>
#include <time.h>
#include <pkglib/mmap.h>
@@ -52,19 +56,29 @@ class pkgCache
friend VerFileIterator;
// These are all the constants used in the cache structures
- enum DepType {Depends=1,PreDepends=2,Suggests=3,Recommends=4,
- Conflicts=5,Replaces=6};
- enum VerPriority {Important=1,Required=2,Standard=3,Optional=5,Extra=5};
- enum PkgSelectedState {Unknown=0,Install=1,Hold=2,DeInstall=3,Purge=4};
- enum PkgFlags {Auto=(1<<0),New=(1<<1),Obsolete=(1<<2),Essential=(1<<3),
- ImmediateConf=(1<<4)};
- enum PkgInstState {Ok=0,ReInstReq=1,HoldInst=2,HoldReInstReq=3};
- enum PkgCurrentState {NotInstalled=0,UnPacked=1,HalfConfigured=2,
- UnInstalled=3,HalfInstalled=4,ConfigFiles=5,
- Installed=6};
- enum PkgFFlags {NotSource=(1<<0)};
- enum DepCompareOp {Or=0x10,NoOp=0,LessEq=0x1,GreaterEq=0x2,Less=0x3,
- Greater=0x4,Equals=0x5,NotEquals=0x6};
+ struct Dep
+ {
+ enum DepType {Depends=1,PreDepends=2,Suggests=3,Recommends=4,
+ Conflicts=5,Replaces=6};
+ enum DepCompareOp {Or=0x10,NoOp=0,LessEq=0x1,GreaterEq=0x2,Less=0x3,
+ Greater=0x4,Equals=0x5,NotEquals=0x6};
+ };
+
+ struct State
+ {
+ enum VerPriority {Important=1,Required=2,Standard=3,Optional=5,Extra=5};
+ enum PkgSelectedState {Unknown=0,Install=1,Hold=2,DeInstall=3,Purge=4};
+ enum PkgInstState {Ok=0,ReInstReq=1,HoldInst=2,HoldReInstReq=3};
+ enum PkgCurrentState {NotInstalled=0,UnPacked=1,HalfConfigured=2,
+ UnInstalled=3,HalfInstalled=4,ConfigFiles=5,Installed=6};
+ };
+
+ struct Flag
+ {
+ enum PkgFlags {Auto=(1<<0),New=(1<<1),Obsolete=(1<<2),Essential=(1<<3),
+ ImmediateConf=(1<<4)};
+ enum PkgFFlags {NotSource=(1<<0)};
+ };
protected:
diff --git a/apt-pkg/pkgcachegen.cc b/apt-pkg/pkgcachegen.cc
index acc05f133..aac3f77d9 100644
--- a/apt-pkg/pkgcachegen.cc
+++ b/apt-pkg/pkgcachegen.cc
@@ -1,6 +1,6 @@
// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: pkgcachegen.cc,v 1.6 1998/07/05 05:53:52 jgg Exp $
+// $Id: pkgcachegen.cc,v 1.7 1998/07/07 04:17:04 jgg Exp $
/* ######################################################################
Package Cache Generator - Generator for the cache structure.
@@ -10,6 +10,10 @@
##################################################################### */
/*}}}*/
// Include Files /*{{{*/
+#ifdef __GNUG__
+#pragma implementation "pkglib/pkgcachegen.h"
+#endif
+
#include <pkglib/pkgcachegen.h>
#include <pkglib/error.h>
#include <pkglib/version.h>
diff --git a/apt-pkg/pkgcachegen.h b/apt-pkg/pkgcachegen.h
index 395afdc83..c883828eb 100644
--- a/apt-pkg/pkgcachegen.h
+++ b/apt-pkg/pkgcachegen.h
@@ -1,6 +1,6 @@
// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: pkgcachegen.h,v 1.3 1998/07/05 05:33:57 jgg Exp $
+// $Id: pkgcachegen.h,v 1.4 1998/07/07 04:17:05 jgg Exp $
/* ######################################################################
Package Cache Generator - Generator for the cache structure.
@@ -13,6 +13,10 @@
#ifndef PKGLIB_PKGCACHEGEN_H
#define PKGLIB_PKGCACHEGEN_H
+#ifdef __GNUG__
+#pragma interface "pkglib/pkgcachegen.h"
+#endif
+
#include <pkglib/pkgcache.h>
class pkgCacheGenerator
diff --git a/apt-pkg/sourcelist.cc b/apt-pkg/sourcelist.cc
new file mode 100644
index 000000000..62d5e6fcd
--- /dev/null
+++ b/apt-pkg/sourcelist.cc
@@ -0,0 +1,465 @@
+// -*- mode: cpp; mode: fold -*-
+// Description /*{{{*/
+// $Id: sourcelist.cc,v 1.1 1998/07/07 04:17:06 jgg Exp $
+/* ######################################################################
+
+ List of Sources
+
+ ##################################################################### */
+ /*}}}*/
+// Include Files /*{{{*/
+#ifdef __GNUG__
+#pragma implementation "pkglib/sourcelist.h"
+#endif
+
+#include <pkglib/sourcelist.h>
+#include <pkglib/error.h>
+#include <pkglib/fileutl.h>
+#include <strutl.h>
+#include <options.h>
+
+#include <fstream.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/stat.h>
+ /*}}}*/
+
+// SourceList::pkgSourceList - Constructors /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+pkgSourceList::pkgSourceList()
+{
+}
+
+pkgSourceList::pkgSourceList(string File)
+{
+ Read(File);
+}
+ /*}}}*/
+// SourceList::ReadMainList - Read the main source list from etc /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool pkgSourceList::ReadMainList()
+{
+ return Read(PKG_DEB_CF_SOURCELIST);
+}
+ /*}}}*/
+// SourceList::Read - Parse the sourcelist file /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool pkgSourceList::Read(string File)
+{
+ // Open the stream for reading
+ ifstream F(File.c_str(),ios::in | ios::nocreate);
+ if (!F != 0)
+ return _error->Errno("ifstream::ifstream","Opening %s",File.c_str());
+
+ List.erase(List.begin(),List.end());
+ char Buffer[300];
+
+ int CurLine = 0;
+ while (F.eof() == false)
+ {
+ F.getline(Buffer,sizeof(Buffer));
+ CurLine++;
+ _strtabexpand(Buffer,sizeof(Buffer));
+ _strstrip(Buffer);
+
+ // Comment or blank
+ if (Buffer[0] == '#' || Buffer[0] == 0)
+ continue;
+
+ // Grok it
+ string Type;
+ string URI;
+ Item Itm;
+ char *C = Buffer;
+ if (ParseQuoteWord(C,Type) == false)
+ return _error->Error("Malformed line %u in source list %s (type)",CurLine,File.c_str());
+ if (ParseQuoteWord(C,URI) == false)
+ return _error->Error("Malformed line %u in source list %s (URI)",CurLine,File.c_str());
+ if (ParseQuoteWord(C,Itm.Dist) == false)
+ return _error->Error("Malformed line %u in source list %s (dist)",CurLine,File.c_str());
+ if (Itm.SetType(Type) == false)
+ return _error->Error("Malformed line %u in source list %s (type parse)",CurLine,File.c_str());
+ if (Itm.SetURI(URI) == false)
+ return _error->Error("Malformed line %u in source list %s (URI parse)",CurLine,File.c_str());
+
+ // Check for an absolute dists specification.
+ if (Itm.Dist.empty() == false && Itm.Dist[Itm.Dist.size() - 1] == '/')
+ {
+ if (ParseQuoteWord(C,Itm.Section) == true)
+ return _error->Error("Malformed line %u in source list %s (Absolute dist)",CurLine,File.c_str());
+ Itm.Dist = SubstVar(Itm.Dist,"$(ARCH)",PKG_DEB_ARCH);
+ List.push_back(Itm);
+ continue;
+ }
+
+ // Grab the rest of the dists
+ if (ParseQuoteWord(C,Itm.Section) == false)
+ return _error->Error("Malformed line %u in source list %s (dist parse)",CurLine,File.c_str());
+
+ do
+ {
+ List.push_back(Itm);
+ }
+ while (ParseQuoteWord(C,Itm.Section) == true);
+ }
+ return true;
+}
+ /*}}}*/
+// SourceList::SanitizeURI - Hash the uri /*{{{*/
+// ---------------------------------------------------------------------
+/* This converts a URI into a safe filename. It quotes all unsafe characters
+ and converts / to _ and removes the scheme identifier. */
+string pkgSourceList::SanitizeURI(string URI)
+{
+ string::const_iterator I = URI.begin() + URI.find(':') + 1;
+ for (; I < URI.end() && *I == '/'; I++);
+
+ // "\x00-\x20{}|\\\\^\\[\\]<>\"\x7F-\xFF";
+ URI = QuoteString(string(I,URI.end() - I),"\\|{}[]<>\"^~_=!@#$%^&*");
+ string::iterator J = URI.begin();
+ for (; J != URI.end(); J++)
+ if (*J == '/')
+ *J = '_';
+ return URI;
+}
+ /*}}}*/
+// SourceList::MatchPkgFile - Find the package file that has the ver /*{{{*/
+// ---------------------------------------------------------------------
+/* This will return List.end() if it could not find the matching
+ file */
+pkgSourceList::const_iterator pkgSourceList::MatchPkgFile(pkgCache::VerIterator Ver)
+{
+ string Base = PKG_DEB_ST_LIST;
+ for (const_iterator I = List.begin(); I != List.end(); I++)
+ {
+ string URI = I->PackagesURI();
+ switch (I->Type)
+ {
+ case Item::Deb:
+ if (Base + SanitizeURI(URI) == Ver.File().FileName())
+ return I;
+ break;
+ };
+ }
+ return List.end();
+}
+ /*}}}*/
+// SourceList::Item << - Writes the item to a stream /*{{{*/
+// ---------------------------------------------------------------------
+/* This is not suitable for rebuilding the sourcelist file but it good for
+ debugging. */
+ostream &operator <<(ostream &O,pkgSourceList::Item &Itm)
+{
+ O << Itm.Type << ' ' << Itm.URI << ' ' << Itm.Dist << ' ' << Itm.Section;
+ return O;
+}
+ /*}}}*/
+// SourceList::Item::SetType - Sets the distribution type /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool pkgSourceList::Item::SetType(string S)
+{
+ if (S == "deb")
+ {
+ Type = Deb;
+ return true;
+ }
+
+ return true;
+}
+ /*}}}*/
+// SourceList::Item::SetURI - Set the URI /*{{{*/
+// ---------------------------------------------------------------------
+/* For simplicity we strip the scheme off the uri */
+bool pkgSourceList::Item::SetURI(string S)
+{
+ if (S.empty() == true)
+ return false;
+
+ if (S.find(':') == string::npos)
+ return false;
+
+ S = SubstVar(S,"$(ARCH)",PKG_DEB_ARCH);
+
+ // Make sure that the URN is / postfixed
+ URI = S;
+ if (URI[URI.size() - 1] != '/')
+ URI += '/';
+
+ return true;
+}
+ /*}}}*/
+// SourceList::Item::PackagesURI - Returns a URI to the packages file /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+string pkgSourceList::Item::PackagesURI() const
+{
+ string Res;
+ switch (Type)
+ {
+ case Deb:
+ if (Dist[Dist.size() - 1] == '/')
+ Res = URI + Dist;
+ else
+ Res = URI + "dists/" + Dist + '/' + Section +
+ "/binary-" + PKG_DEB_ARCH + '/';
+
+ Res += "Packages";
+ break;
+ };
+ return Res;
+}
+ /*}}}*/
+// SourceList::Item::PackagesInfo - Shorter version of the URI /*{{{*/
+// ---------------------------------------------------------------------
+/* This is a shorter version that is designed to be < 60 chars or so */
+string pkgSourceList::Item::PackagesInfo() const
+{
+ string Res;
+ switch (Type)
+ {
+ case Deb:
+ Res += SiteOnly(URI) + ' ';
+ if (Dist[Dist.size() - 1] == '/')
+ Res += Dist;
+ else
+ Res += Dist + '/' + Section;
+
+ Res += " Packages";
+ break;
+ };
+ return Res;
+}
+ /*}}}*/
+// SourceList::Item::ArchiveInfo - Shorter version of the archive spec /*{{{*/
+// ---------------------------------------------------------------------
+/* This is a shorter version that is designed to be < 60 chars or so */
+string pkgSourceList::Item::ArchiveInfo(pkgCache::VerIterator Ver) const
+{
+ string Res;
+ switch (Type)
+ {
+ case Deb:
+ Res += SiteOnly(URI) + ' ';
+ if (Dist[Dist.size() - 1] == '/')
+ Res += Dist;
+ else
+ Res += Dist + '/' + Section;
+
+ Res += " ";
+ Res += Ver.ParentPkg().Name();
+ break;
+ };
+ return Res;
+}
+ /*}}}*/
+// SourceList::Item::ArchiveURI - Returns a URI to the given archive /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+string pkgSourceList::Item::ArchiveURI(string File) const
+{
+ string Res;
+ switch (Type)
+ {
+ case Deb:
+ Res = URI + File;
+ break;
+ };
+ return Res;
+}
+ /*}}}*/
+// SourceList::Item::SiteOnly - Strip off the path part of a URI /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+string pkgSourceList::Item::SiteOnly(string URI) const
+{
+ unsigned int Pos = URI.find(':');
+ if (Pos == string::npos || Pos + 3 > URI.length())
+ return URI;
+ if (URI[Pos + 1] != '/' || URI[Pos + 2] != '/')
+ return URI;
+
+ Pos = URI.find('/',Pos + 3);
+ if (Pos == string::npos)
+ return URI;
+ return string(URI,0,Pos);
+}
+ /*}}}*/
+
+// UpdateMeta - Update the meta information /*{{{*/
+// ---------------------------------------------------------------------
+/* The meta information is package files, revision information and mirror
+ lists. */
+bool pkgUpdateMeta(pkgSourceList &List,pkgAquire &Engine)
+{
+ if (Engine.OutputDir(PKG_DEB_ST_LIST) == false)
+ return false;
+
+ for (pkgSourceList::const_iterator I = List.begin(); I != List.end(); I++)
+ {
+ string URI = I->PackagesURI();
+ string GetInfo = I->PackagesInfo();
+ switch (I->Type)
+ {
+ case pkgSourceList::Item::Deb:
+ if (Engine.Get(URI + ".gz",List.SanitizeURI(URI),GetInfo) == false)
+ return false;
+ break;
+ };
+ }
+
+ return true;
+}
+ /*}}}*/
+// MakeSrcCache - Generate a cache file of all the package files /*{{{*/
+// ---------------------------------------------------------------------
+/* This goes over the source list and builds a cache of all the package
+ files. */
+bool pkgMakeSrcCache(pkgSourceList &List)
+{
+ // First we date check the cache
+ bool Bad = false;
+ while (Bad == false)
+ {
+ if (FileExists(PKG_DEB_CA_SRCCACHE) == false)
+ break;
+
+ pkgCache Cache(PKG_DEB_CA_SRCCACHE,true,true);
+ if (_error->PendingError() == true)
+ {
+ _error->Discard();
+ break;
+ }
+
+ // They are certianly out of sync
+ if (Cache.Head().PackageFileCount != List.size())
+ break;
+
+ for (pkgCache::PkgFileIterator F(Cache); F.end() == false; F++)
+ {
+ // Search for a match in the source list
+ Bad = true;
+ for (pkgSourceList::const_iterator I = List.begin();
+ I != List.end(); I++)
+ {
+ string File = string(PKG_DEB_ST_LIST) +
+ List.SanitizeURI(I->PackagesURI());
+ if (F.FileName() == File)
+ {
+ Bad = false;
+ break;
+ }
+ }
+
+ // Check if the file matches what was cached
+ Bad |= !F.IsOk();
+ if (Bad == true)
+ break;
+ }
+
+ if (Bad == false)
+ return true;
+ }
+
+ unlink(PKG_DEB_CA_SRCCACHE);
+ pkgCache::MergeState Merge(PKG_DEB_CA_SRCCACHE);
+ if (_error->PendingError() == true)
+ return false;
+
+ for (pkgSourceList::const_iterator I = List.begin(); I != List.end(); I++)
+ {
+ string File = string(PKG_DEB_ST_LIST) + List.SanitizeURI(I->PackagesURI());
+ if (Merge.MergePackageFile(File,"??","??") == false)
+ return false;
+ }
+
+ return true;
+}
+ /*}}}*/
+// MakeStatusCache - Generates a cache that includes the status files /*{{{*/
+// ---------------------------------------------------------------------
+/* This copies the package source cache and then merges the status and
+ xstatus files into it. */
+bool pkgMakeStatusCache()
+{
+ // Quickly check if the existing package cache is ok
+ bool Bad = false;
+ while (Bad == false)
+ {
+ if (FileExists(PKG_DEB_CA_PKGCACHE) == false)
+ break;
+
+ /* We check the dates of the two caches. This takes care of most things
+ quickly and easially */
+ struct stat Src;
+ struct stat Pkg;
+ if (stat(PKG_DEB_CA_PKGCACHE,&Pkg) != 0 ||
+ stat(PKG_DEB_CA_SRCCACHE,&Src) != 0)
+ break;
+ if (difftime(Src.st_mtime,Pkg.st_mtime) > 0)
+ break;
+
+ pkgCache Cache(PKG_DEB_CA_PKGCACHE,true,true);
+ if (_error->PendingError() == true)
+ {
+ _error->Discard();
+ break;
+ }
+
+ for (pkgCache::PkgFileIterator F(Cache); F.end() == false; F++)
+ {
+ if (F.IsOk() == false)
+ {
+ Bad = true;
+ break;
+ }
+ }
+
+ if (Bad == false)
+ return true;
+ }
+
+ // Check the integrity of the source cache.
+ {
+ pkgCache Cache(PKG_DEB_CA_SRCCACHE,true,true);
+ if (_error->PendingError() == true)
+ return false;
+ }
+
+ // Sub scope so that merge destructs before we rename the file...
+ string Cache = PKG_DEB_CA_PKGCACHE ".new";
+ {
+ if (CopyFile(PKG_DEB_CA_SRCCACHE,Cache) == false)
+ return false;
+
+ pkgCache::MergeState Merge(Cache);
+ if (_error->PendingError() == true)
+ return false;
+
+ // Merge in the user status file
+ if (FileExists(PKG_DEB_ST_USERSTATUS) == true)
+ if (Merge.MergePackageFile(PKG_DEB_ST_USERSTATUS,"status","0",
+ pkgFLAG_NotSource) == false)
+ return false;
+
+ // Merge in the extra status file
+ if (FileExists(PKG_DEB_ST_XSTATUS) == true)
+ if (Merge.MergePackageFile(PKG_DEB_ST_XSTATUS,"status","0",
+ pkgFLAG_NotSource) == false)
+ return false;
+
+ // Merge in the status file
+ if (Merge.MergePackageFile("/var/lib/dpkg/status","status","0",
+ pkgFLAG_NotSource) == false)
+ return false;
+ }
+
+ if (rename(Cache.c_str(),PKG_DEB_CA_PKGCACHE) != 0)
+ return false;
+
+ return true;
+}
+ /*}}}*/
diff --git a/apt-pkg/sourcelist.h b/apt-pkg/sourcelist.h
new file mode 100644
index 000000000..986d5e9e8
--- /dev/null
+++ b/apt-pkg/sourcelist.h
@@ -0,0 +1,78 @@
+// -*- mode: cpp; mode: fold -*-
+// Description /*{{{*/
+// $Id: sourcelist.h,v 1.1 1998/07/07 04:17:06 jgg Exp $
+/* ######################################################################
+
+ SourceList - Manage a list of sources
+
+ The Source List class provides access to a list of sources. It
+ can read them from a file and generate a list of all the permutations.
+
+ ##################################################################### */
+ /*}}}*/
+// Header section: pkglib
+#ifndef PKGLIB_SOURCELIST_H
+#define PKGLIB_SOURCELIST_H
+
+#include <string>
+#include <vector>
+#include <iostream.h>
+#include <pkglib/pkgcache.h>
+
+#ifdef __GNUG__
+#pragma interface "pkglib/sourcelist.h"
+#endif
+
+class pkgAquire;
+class pkgSourceList
+{
+ public:
+
+ /* Each item in the source list, each line can have more than one
+ item */
+ struct Item
+ {
+ enum {Deb} Type;
+
+ string URI;
+ string Dist;
+ string Section;
+
+ bool SetType(string S);
+ bool SetURI(string S);
+ string PackagesURI() const;
+ string PackagesInfo() const;
+ string SiteOnly(string URI) const;
+ string ArchiveInfo(pkgCache::VerIterator Ver) const;
+ string ArchiveURI(string File) const;
+ };
+ typedef vector<Item>::const_iterator const_iterator;
+
+ protected:
+
+ vector<Item> List;
+
+ public:
+
+ bool ReadMainList();
+ bool Read(string File);
+ string SanitizeURI(string URI);
+ const_iterator MatchPkgFile(pkgCache::VerIterator Ver);
+
+ // List accessors
+ inline const_iterator begin() const {return List.begin();};
+ inline const_iterator end() const {return List.end();};
+ inline unsigned int size() const {return List.size();};
+ inline bool empty() const {return List.empty();};
+
+ pkgSourceList();
+ pkgSourceList(string File);
+};
+
+bool pkgUpdateMeta(pkgSourceList &List,pkgAquire &Engine);
+bool pkgMakeSrcCache(pkgSourceList &List);
+bool pkgMakeStatusCache();
+
+ostream &operator <<(ostream &O,pkgSourceList::Item &Itm);
+
+#endif
diff --git a/apt-pkg/tagfile.cc b/apt-pkg/tagfile.cc
index 9710b7615..b8845a3b1 100644
--- a/apt-pkg/tagfile.cc
+++ b/apt-pkg/tagfile.cc
@@ -1,6 +1,6 @@
// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: tagfile.cc,v 1.4 1998/07/05 05:33:58 jgg Exp $
+// $Id: tagfile.cc,v 1.5 1998/07/07 04:17:06 jgg Exp $
/* ######################################################################
Fast scanner for RFC-822 type header information
@@ -11,6 +11,10 @@
##################################################################### */
/*}}}*/
// Include Files /*{{{*/
+#ifdef __GNUG__
+#pragma implementation "pkglib/tagfile.h"
+#endif
+
#include <pkglib/tagfile.h>
#include <pkglib/error.h>
diff --git a/apt-pkg/tagfile.h b/apt-pkg/tagfile.h
index 661ac4f23..c1fffcf13 100644
--- a/apt-pkg/tagfile.h
+++ b/apt-pkg/tagfile.h
@@ -1,6 +1,6 @@
// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: tagfile.h,v 1.2 1998/07/05 05:33:59 jgg Exp $
+// $Id: tagfile.h,v 1.3 1998/07/07 04:17:07 jgg Exp $
/* ######################################################################
Fast scanner for RFC-822 type header information
@@ -21,6 +21,10 @@
#ifndef PKGLIB_TAGFILE_H
#define PKGLIB_TAGFILE_H
+#ifdef __GNUG__
+#pragma interface "pkglib/tagfile.h"
+#endif
+
#include <pkglib/fileutl.h>
class pkgTagSection
diff --git a/apt-pkg/version.cc b/apt-pkg/version.cc
index 174622c91..7eb85726c 100644
--- a/apt-pkg/version.cc
+++ b/apt-pkg/version.cc
@@ -1,6 +1,6 @@
// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: version.cc,v 1.2 1998/07/04 05:57:40 jgg Exp $
+// $Id: version.cc,v 1.3 1998/07/07 04:17:08 jgg Exp $
/* ######################################################################
Version - Version string
@@ -17,6 +17,10 @@
##################################################################### */
/*}}}*/
// Include Files /*{{{*/
+#ifdef __GNUG__
+#pragma implementation "pkglib/version.h"
+#endif
+
#include <pkglib/version.h>
#include <pkglib/pkgcache.h>
@@ -212,32 +216,32 @@ bool pkgCheckDep(const char *DepVer,const char *PkgVer,int Op)
int Res = pkgVersionCompare(PkgVer,DepVer);
switch (Op & 0x0F)
{
- case pkgCache::LessEq:
+ case pkgCache::Dep::LessEq:
if (Res <= 0)
return true;
break;
- case pkgCache::GreaterEq:
+ case pkgCache::Dep::GreaterEq:
if (Res >= 0)
return true;
break;
- case pkgCache::Less:
+ case pkgCache::Dep::Less:
if (Res < 0)
return true;
break;
- case pkgCache::Greater:
+ case pkgCache::Dep::Greater:
if (Res > 0)
return true;
break;
- case pkgCache::Equals:
+ case pkgCache::Dep::Equals:
if (Res == 0)
return true;
break;
- case pkgCache::NotEquals:
+ case pkgCache::Dep::NotEquals:
if (Res != 0)
return true;
break;
diff --git a/apt-pkg/version.h b/apt-pkg/version.h
index a30246946..3ced5d3e4 100644
--- a/apt-pkg/version.h
+++ b/apt-pkg/version.h
@@ -1,6 +1,6 @@
// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: version.h,v 1.1 1998/07/02 02:58:13 jgg Exp $
+// $Id: version.h,v 1.2 1998/07/07 04:17:09 jgg Exp $
/* ######################################################################
Version - Version string
@@ -15,6 +15,10 @@
#ifndef PKGLIB_VERSION_H
#define PKGLIB_VERSION_H
+#ifdef __GNUG__
+#pragma interface "pkglib/version.h"
+#endif
+
#include <string>
class pkgVersion