Просмотр исходного кода

Sync
Author: jgg
Date: 1998-07-07 04:17:00 GMT
Sync

Arch Librarian лет назад: 22
Родитель
Сommit
6c139d6e36

+ 732 - 0
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;
+}
+									/*}}}*/

+ 91 - 0
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

+ 15 - 6
apt-pkg/cacheiterators.h

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
 // 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
    Cache Iterators - Iterators for navigating the cache structure
@@ -21,7 +21,8 @@
    The DepIterator can iterate over two lists, a list of 'version depends'
    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
    or a list of 'package reverse depends'. The type is determined by the
    structure passed to the constructor, which should be the structure
    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
    This header is not user includable, please use pkglib/pkgcache.h
    
    
@@ -31,6 +32,10 @@
 #ifndef PKGLIB_CACHEITERATORS_H
 #ifndef PKGLIB_CACHEITERATORS_H
 #define PKGLIB_CACHEITERATORS_H
 #define PKGLIB_CACHEITERATORS_H
 
 
+#ifdef __GNUG__
+#pragma interface "pkglib/cacheiterators.h"
+#endif 
+
 // Package Iterator
 // Package Iterator
 class pkgCache::PkgIterator
 class pkgCache::PkgIterator
 {
 {
@@ -57,6 +62,7 @@ class pkgCache::PkgIterator
    inline Package const &operator *() const {return *Pkg;};
    inline Package const &operator *() const {return *Pkg;};
    inline operator Package *() {return Pkg == Owner->PkgP?0:Pkg;};
    inline operator Package *() {return Pkg == Owner->PkgP?0:Pkg;};
    inline operator Package const *() const {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 *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 *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;};
    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 Version const &operator *() const {return *Ver;};
    inline operator Version *() {return Ver == Owner.VerP?0:Ver;};
    inline operator Version *() {return Ver == Owner.VerP?0:Ver;};
    inline operator Version const *() const {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 *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 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 PkgIterator ParentPkg() const {return PkgIterator(Owner,Owner.PkgP + Ver->ParentPkg);};
    inline DepIterator DependsList() const;
    inline DepIterator DependsList() const;
    inline PrvIterator ProvidesList() const;
    inline PrvIterator ProvidesList() const;
-   inline unsigned long Index() const {return Ver - Owner.VerP;};
    inline VerFileIterator FileList() const;
    inline VerFileIterator FileList() const;
+   inline unsigned long Index() const {return Ver - Owner.VerP;};
 
 
    inline VerIterator(pkgCache &Owner,Version *Trg = 0) : Ver(Trg), Owner(Owner) 
    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 Dependency const &operator *() const {return *Dep;};
    inline operator Dependency *() {return Dep == Owner->DepP?0:Dep;};
    inline operator Dependency *() {return Dep == Owner->DepP?0:Dep;};
    inline operator Dependency const *() const {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 const char *TargetVer() const {return Dep->Version == 0?0:Owner->StrP + Dep->Version;};
    inline PkgIterator TargetPkg() {return PkgIterator(*Owner,Owner->PkgP + Dep->Package);};
    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 PkgIterator SmartTargetPkg() {PkgIterator R(*Owner);SmartTargetPkg(R);return R;};
    inline VerIterator ParentVer() {return VerIterator(*Owner,Owner->VerP + Dep->ParentVer);};
    inline VerIterator ParentVer() {return VerIterator(*Owner,Owner->VerP + Dep->ParentVer);};
    inline PkgIterator ParentPkg() {return PkgIterator(*Owner,Owner->PkgP + Owner->VerP[Dep->ParentVer].ParentPkg);};
    inline PkgIterator ParentPkg() {return PkgIterator(*Owner,Owner->PkgP + Owner->VerP[Dep->ParentVer].ParentPkg);};
-   bool IsCritical();
    inline bool Reverse() {return Type == DepRev;};
    inline bool Reverse() {return Type == DepRev;};
    inline unsigned long Index() const {return Dep - Owner->DepP;};
    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) :
    inline DepIterator(pkgCache &Owner,Dependency *Trg,Version * = 0) :
           Dep(Trg), Type(DepVer), Owner(&Owner) 
           Dep(Trg), Type(DepVer), Owner(&Owner) 
@@ -208,6 +216,7 @@ class pkgCache::PrvIterator
    inline Provides const &operator *() const {return *Prv;};
    inline Provides const &operator *() const {return *Prv;};
    inline operator Provides *() {return Prv == Owner->ProvideP?0:Prv;};
    inline operator Provides *() {return Prv == Owner->ProvideP?0:Prv;};
    inline operator Provides const *() const {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 *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 const char *ProvideVersion() const {return Prv->ProvideVersion == 0?0:Owner->StrP + Prv->ProvideVersion;};
    inline PkgIterator ParentPkg() {return PkgIterator(*Owner,Owner->PkgP + Prv->ParentPkg);};
    inline PkgIterator ParentPkg() {return PkgIterator(*Owner,Owner->PkgP + Prv->ParentPkg);};

+ 137 - 0
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;
+}
+									/*}}}*/

+ 61 - 0
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

+ 55 - 19
apt-pkg/contrib/error.cc

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
 // 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
    Global Erorr Class - Global error mechanism
@@ -14,6 +14,10 @@
    ##################################################################### */
    ##################################################################### */
 									/*}}}*/
 									/*}}}*/
 // Include Files							/*{{{*/
 // Include Files							/*{{{*/
+#ifdef __GNUG__
+#pragma implementation "pkglib/error.h"
+#endif 
+
 #include <errno.h>
 #include <errno.h>
 #include <stdio.h>
 #include <stdio.h>
 #include <string.h>
 #include <string.h>
@@ -27,7 +31,7 @@ GlobalError *_error = new GlobalError;
 // GlobalError::GlobalError - Constructor				/*{{{*/
 // 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));
    sprintf(S + strlen(S)," - %s (%i %s)",Function,errno,strerror(errno));
 
 
    // Put it on the list
    // 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;
    PendingFlag = true;
 
 
@@ -72,10 +76,10 @@ bool GlobalError::Error(const char *Description,...)
    vsprintf(S,Description,args);
    vsprintf(S,Description,args);
 
 
    // Put it on the list
    // 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;
    PendingFlag = true;
    
    
@@ -95,10 +99,10 @@ bool GlobalError::Warning(const char *Description,...)
    vsprintf(S,Description,args);
    vsprintf(S,Description,args);
 
 
    // Put it on the list
    // 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;
    return false;
 }
 }
@@ -109,12 +113,17 @@ bool GlobalError::Warning(const char *Description,...)
    true if the message is an error. */
    true if the message is an error. */
 bool GlobalError::PopMessage(string &Text)
 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..
    // This really should check the list to see if only warnings are left..
-   if (empty())
+   if (List == 0)
       PendingFlag = false;
       PendingFlag = false;
    
    
    return Ret;
    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;
+}
+									/*}}}*/

+ 10 - 5
apt-pkg/contrib/error.h

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
 // 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
    Global Erorr Class - Global error mechanism
@@ -41,8 +41,11 @@
 #ifndef PKGLIB_ERROR_H
 #ifndef PKGLIB_ERROR_H
 #define PKGLIB_ERROR_H
 #define PKGLIB_ERROR_H
 
 
+#ifdef __GNUG__
+#pragma interface "pkglib/error.h"
+#endif 
+
 #include <string>
 #include <string>
-#include <vector.h>
 
 
 class GlobalError
 class GlobalError
 {
 {
@@ -50,10 +53,12 @@ class GlobalError
    {
    {
       string Text;
       string Text;
       bool Error;
       bool Error;
+      Item *Next;
    };
    };
    
    
-   vector<Item> List;
+   Item *List;
    bool PendingFlag;
    bool PendingFlag;
+   void Insert(Item *I);
    
    
    public:
    public:
 
 
@@ -67,9 +72,9 @@ class GlobalError
 
 
    // Simple accessors
    // Simple accessors
    inline bool PendingError() {return PendingFlag;};
    inline bool PendingError() {return PendingFlag;};
-   inline bool empty() {return List.empty();};
+   inline bool empty() {return List == 0;};
    bool PopMessage(string &Text);
    bool PopMessage(string &Text);
-   void Discard() {List.erase(List.begin(),List.end()); PendingFlag = false;};
+   void Discard();
 
 
    // Usefull routine to dump to cerr
    // Usefull routine to dump to cerr
    void DumpErrors();
    void DumpErrors();

+ 4 - 1
apt-pkg/contrib/fileutl.cc

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
 // 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
    File Utilities
@@ -14,6 +14,9 @@
    ##################################################################### */
    ##################################################################### */
 									/*}}}*/
 									/*}}}*/
 // Include Files							/*{{{*/
 // Include Files							/*{{{*/
+#ifdef __GNUG__
+#pragma implementation "pkglib/fileutl.h"
+#endif 
 #include <pkglib/fileutl.h>
 #include <pkglib/fileutl.h>
 #include <pkglib/error.h>
 #include <pkglib/error.h>
 
 

+ 5 - 1
apt-pkg/contrib/fileutl.h

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
 // 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
    File Utilities
@@ -22,6 +22,10 @@
 #ifndef PKGLIB_FILEUTL_H
 #ifndef PKGLIB_FILEUTL_H
 #define PKGLIB_FILEUTL_H
 #define PKGLIB_FILEUTL_H
 
 
+#ifdef __GNUG__
+#pragma interface "pkglib/fileutl.h"
+#endif 
+
 #include <string>
 #include <string>
 
 
 class File
 class File

+ 5 - 1
apt-pkg/contrib/mmap.cc

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
 // 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().
    MMap Class - Provides 'real' mmap or a faked mmap using read().
@@ -21,6 +21,10 @@
    ##################################################################### */
    ##################################################################### */
 									/*}}}*/
 									/*}}}*/
 // Include Files							/*{{{*/
 // Include Files							/*{{{*/
+#ifdef __GNUG__
+#pragma implementation "pkglib/mmap.h"
+#endif 
+
 #define _BSD_SOURCE
 #define _BSD_SOURCE
 #include <pkglib/mmap.h>
 #include <pkglib/mmap.h>
 #include <pkglib/error.h>
 #include <pkglib/error.h>

+ 5 - 1
apt-pkg/contrib/mmap.h

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
 // 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().
    MMap Class - Provides 'real' mmap or a faked mmap using read().
@@ -26,6 +26,10 @@
 #ifndef PKGLIB_MMAP_H
 #ifndef PKGLIB_MMAP_H
 #define PKGLIB_MMAP_H
 #define PKGLIB_MMAP_H
 
 
+#ifdef __GNUG__
+#pragma interface "pkglib/mmap.h"
+#endif
+
 #include <string>
 #include <string>
 #include <pkglib/fileutl.h>
 #include <pkglib/fileutl.h>
 
 

+ 343 - 0
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;
+}
+									/*}}}*/

+ 36 - 0
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

+ 45 - 45
apt-pkg/deb/deblistparser.cc

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
 // 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.
    Package Cache Generator - Generator for the cache structure.
@@ -147,27 +147,27 @@ bool debListParser::NewVersion(pkgCache::VerIterator Ver)
    const char *Stop;
    const char *Stop;
    if (Section.Find("Priority",Start,Stop) == true)
    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,
       if (GrabWord(string(Start,Stop-Start),PrioList,
 		   _count(PrioList),Ver->Priority) == false)
 		   _count(PrioList),Ver->Priority) == false)
 	 return _error->Error("Malformed Priority line");
 	 return _error->Error("Malformed Priority line");
    }
    }
 
 
-   if (ParseDepends(Ver,"Depends",pkgCache::Depends) == false)
+   if (ParseDepends(Ver,"Depends",pkgCache::Dep::Depends) == false)
       return false;
       return false;
-   if (ParseDepends(Ver,"PreDepends",pkgCache::PreDepends) == false)
+   if (ParseDepends(Ver,"PreDepends",pkgCache::Dep::PreDepends) == false)
       return false;
       return false;
-   if (ParseDepends(Ver,"Suggests",pkgCache::Suggests) == false)
+   if (ParseDepends(Ver,"Suggests",pkgCache::Dep::Suggests) == false)
       return false;
       return false;
-   if (ParseDepends(Ver,"Recommends",pkgCache::Recommends) == false)
+   if (ParseDepends(Ver,"Recommends",pkgCache::Dep::Recommends) == false)
       return false;
       return false;
-   if (ParseDepends(Ver,"Conflicts",pkgCache::Conflicts) == false)
+   if (ParseDepends(Ver,"Conflicts",pkgCache::Dep::Conflicts) == false)
       return false;
       return false;
-   if (ParseDepends(Ver,"Replaces",pkgCache::Depends) == false)
+   if (ParseDepends(Ver,"Replaces",pkgCache::Dep::Depends) == false)
       return false;
       return false;
 
 
    if (ParseProvides(Ver) == false)
    if (ParseProvides(Ver) == false)
@@ -186,9 +186,9 @@ bool debListParser::UsePackage(pkgCache::PkgIterator Pkg,
    if (Pkg->Section == 0)
    if (Pkg->Section == 0)
       if ((Pkg->Section = UniqFindTagWrite("Section")) == 0)
       if ((Pkg->Section = UniqFindTagWrite("Section")) == 0)
 	 return false;
 	 return false;
-   if (HandleFlag("Essential",Pkg->Flags,pkgCache::Essential) == false)
+   if (HandleFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false)
       return false;
       return false;
-   if (HandleFlag("Immediate-Configure",Pkg->Flags,pkgCache::ImmediateConf) == false)
+   if (HandleFlag("Immediate-Configure",Pkg->Flags,pkgCache::Flag::ImmediateConf) == false)
       return false;
       return false;
    if (ParseStatus(Pkg,Ver) == false)
    if (ParseStatus(Pkg,Ver) == false)
       return false;
       return false;
@@ -223,11 +223,11 @@ bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg,
       return _error->Error("Malformed Status line");
       return _error->Error("Malformed Status line");
 
 
    // Process the want field
    // 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,
    if (GrabWord(string(Start,I-Start),WantList,
 		_count(WantList),Pkg->SelectedState) == false)
 		_count(WantList),Pkg->SelectedState) == false)
       return _error->Error("Malformed 1st word in the Status line");
       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");
       return _error->Error("Malformed status line, no 2nd word");
 
 
    // Process the flag field
    // 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,
    if (GrabWord(string(Start,I-Start),FlagList,
 		_count(FlagList),Pkg->InstState) == false)
 		_count(FlagList),Pkg->InstState) == false)
       return _error->Error("Malformed 2nd word in the Status line");
       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");
       return _error->Error("Malformed Status line, no 3rd word");
 
 
    // Process the flag field
    // 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,
    if (GrabWord(string(Start,I-Start),StatusList,
 		_count(StatusList),Pkg->CurrentState) == false)
 		_count(StatusList),Pkg->CurrentState) == false)
       return _error->Error("Malformed 3rd word in the Status line");
       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
       version as well. Only if it is actually installed.. Otherwise
       the interesting dpkg handling of the status file creates bogus 
       the interesting dpkg handling of the status file creates bogus 
       entries. */
       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)
       if (Ver.end() == true)
 	 _error->Warning("Encountered status field in a non-version description");
 	 _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 == '=')
 	 if (*I == '=')
 	 {
 	 {
 	    I++;
 	    I++;
-	    Op = pkgCache::LessEq;
+	    Op = pkgCache::Dep::LessEq;
 	    break;
 	    break;
 	 }
 	 }
 	 
 	 
 	 if (*I == '<')
 	 if (*I == '<')
 	 {
 	 {
 	    I++;
 	    I++;
-	    Op = pkgCache::Less;
+	    Op = pkgCache::Dep::Less;
 	    break;
 	    break;
 	 }
 	 }
 	 
 	 
 	 // < is the same as <= and << is really Cs < for some reason
 	 // < is the same as <= and << is really Cs < for some reason
-	 Op = pkgCache::LessEq;
+	 Op = pkgCache::Dep::LessEq;
 	 break;
 	 break;
 	 
 	 
 	 case '>':
 	 case '>':
@@ -350,29 +350,29 @@ const char *debListParser::ParseDepends(const char *Start,const char *Stop,
 	 if (*I == '=')
 	 if (*I == '=')
 	 {
 	 {
 	    I++;
 	    I++;
-	    Op = pkgCache::GreaterEq;
+	    Op = pkgCache::Dep::GreaterEq;
 	    break;
 	    break;
 	 }
 	 }
 	 
 	 
 	 if (*I == '>')
 	 if (*I == '>')
 	 {
 	 {
 	    I++;
 	    I++;
-	    Op = pkgCache::Greater;
+	    Op = pkgCache::Dep::Greater;
 	    break;
 	    break;
 	 }
 	 }
 	 
 	 
 	 // > is the same as >= and >> is really Cs > for some reason
 	 // > is the same as >= and >> is really Cs > for some reason
-	 Op = pkgCache::GreaterEq;
+	 Op = pkgCache::Dep::GreaterEq;
 	 break;
 	 break;
 	 
 	 
 	 case '=':
 	 case '=':
-	 Op = pkgCache::Equals;
+	 Op = pkgCache::Dep::Equals;
 	 I++;
 	 I++;
 	 break;
 	 break;
 	 
 	 
 	 // HACK around bad package definitions
 	 // HACK around bad package definitions
 	 default:
 	 default:
-	 Op = pkgCache::Equals;
+	 Op = pkgCache::Dep::Equals;
 	 break;
 	 break;
       }
       }
       
       
@@ -389,13 +389,13 @@ const char *debListParser::ParseDepends(const char *Start,const char *Stop,
    else
    else
    {
    {
       Ver = string();
       Ver = string();
-      Op = pkgCache::NoOp;
+      Op = pkgCache::Dep::NoOp;
    }
    }
    
    
    // Skip whitespace
    // Skip whitespace
    for (;I != Stop && isspace(*I) != 0; I++);
    for (;I != Stop && isspace(*I) != 0; I++);
    if (I != Stop && *I == '|')
    if (I != Stop && *I == '|')
-      Op |= pkgCache::Or;
+      Op |= pkgCache::Dep::Or;
    
    
    if (I == Stop || *I == ',' || *I == '|')
    if (I == Stop || *I == ',' || *I == '|')
    {
    {
@@ -453,7 +453,7 @@ bool debListParser::ParseProvides(pkgCache::VerIterator Ver)
       Start = ParseDepends(Start,Stop,Package,Version,Op);
       Start = ParseDepends(Start,Stop,Package,Version,Op);
       if (Start == 0)
       if (Start == 0)
 	 return _error->Error("Problem parsing Provides line");
 	 return _error->Error("Problem parsing Provides line");
-      if (Op != pkgCache::NoOp)
+      if (Op != pkgCache::Dep::NoOp)
 	 return _error->Error("Malformed provides line");
 	 return _error->Error("Malformed provides line");
 
 
       if (NewProvides(Ver,Package,Version) == false)
       if (NewProvides(Ver,Package,Version) == false)

+ 903 - 0
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;
+}
+									/*}}}*/

+ 189 - 0
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

+ 829 - 0
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;
+}
+									/*}}}*/

+ 123 - 0
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

+ 548 - 0
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();
+}
+									/*}}}*/

+ 84 - 0
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

+ 14 - 10
apt-pkg/pkgcache.cc

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
 // 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
    Package Cache - Accessor code for the cache
@@ -20,6 +20,10 @@
    ##################################################################### */
    ##################################################################### */
 									/*}}}*/
 									/*}}}*/
 // Include Files							/*{{{*/
 // Include Files							/*{{{*/
+#ifdef __GNUG__
+#pragma implementation "pkglib/pkgcache.h"
+#pragma implementation "pkglib/cacheiterators.h"
+#endif 
 #include <pkglib/pkgcache.h>
 #include <pkglib/pkgcache.h>
 #include <pkglib/version.h>
 #include <pkglib/version.h>
 #include <pkglib/error.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. */
 /* By this we mean if it is either cleanly installed or cleanly removed. */
 pkgCache::PkgIterator::OkState pkgCache::PkgIterator::State() const
 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;
       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 NeedsUnpack;
       
       
    return NeedsNothing;
    return NeedsNothing;
@@ -217,8 +221,8 @@ pkgCache::PkgIterator::OkState pkgCache::PkgIterator::State() const
    conflicts. */
    conflicts. */
 bool pkgCache::DepIterator::IsCritical()
 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 true;
    return false;
    return false;
 }
 }
@@ -293,7 +297,7 @@ pkgCache::Version **pkgCache::DepIterator::AllTargets()
 	 if (pkgCheckDep(TargetVer(),I.VerStr(),Dep->CompareOp) == false)
 	 if (pkgCheckDep(TargetVer(),I.VerStr(),Dep->CompareOp) == false)
 	    continue;
 	    continue;
 
 
-	 if (Dep->Type == Conflicts && ParentPkg() == I.ParentPkg())
+	 if (Dep->Type == Dep::Conflicts && ParentPkg() == I.ParentPkg())
 	    continue;
 	    continue;
 	 
 	 
 	 Size++;
 	 Size++;
@@ -307,7 +311,7 @@ pkgCache::Version **pkgCache::DepIterator::AllTargets()
 	 if (pkgCheckDep(TargetVer(),I.ProvideVersion(),Dep->CompareOp) == false)
 	 if (pkgCheckDep(TargetVer(),I.ProvideVersion(),Dep->CompareOp) == false)
 	    continue;
 	    continue;
 	 
 	 
-	 if (Dep->Type == Conflicts && ParentPkg() == I.OwnerPkg())
+	 if (Dep->Type == Dep::Conflicts && ParentPkg() == I.OwnerPkg())
 	    continue;
 	    continue;
 	 
 	 
 	 Size++;
 	 Size++;

+ 28 - 14
apt-pkg/pkgcache.h

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
 // 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
    Cache - Structure definitions for the cache file
@@ -20,6 +20,10 @@
 #ifndef PKGLIB_PKGCACHE_H
 #ifndef PKGLIB_PKGCACHE_H
 #define PKGLIB_PKGCACHE_H
 #define PKGLIB_PKGCACHE_H
 
 
+#ifdef __GNUG__
+#pragma interface "pkglib/pkgcache.h"
+#endif 
+
 #include <string>
 #include <string>
 #include <time.h>
 #include <time.h>
 #include <pkglib/mmap.h>
 #include <pkglib/mmap.h>
@@ -52,19 +56,29 @@ class pkgCache
    friend VerFileIterator;
    friend VerFileIterator;
    
    
    // These are all the constants used in the cache structures
    // 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:
    protected:
    
    

+ 5 - 1
apt-pkg/pkgcachegen.cc

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
 // 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.
    Package Cache Generator - Generator for the cache structure.
@@ -10,6 +10,10 @@
    ##################################################################### */
    ##################################################################### */
 									/*}}}*/
 									/*}}}*/
 // Include Files							/*{{{*/
 // Include Files							/*{{{*/
+#ifdef __GNUG__
+#pragma implementation "pkglib/pkgcachegen.h"
+#endif
+
 #include <pkglib/pkgcachegen.h>
 #include <pkglib/pkgcachegen.h>
 #include <pkglib/error.h>
 #include <pkglib/error.h>
 #include <pkglib/version.h>
 #include <pkglib/version.h>

+ 5 - 1
apt-pkg/pkgcachegen.h

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
 // 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.
    Package Cache Generator - Generator for the cache structure.
@@ -13,6 +13,10 @@
 #ifndef PKGLIB_PKGCACHEGEN_H
 #ifndef PKGLIB_PKGCACHEGEN_H
 #define PKGLIB_PKGCACHEGEN_H
 #define PKGLIB_PKGCACHEGEN_H
 
 
+#ifdef __GNUG__
+#pragma interface "pkglib/pkgcachegen.h"
+#endif 
+
 #include <pkglib/pkgcache.h>
 #include <pkglib/pkgcache.h>
 
 
 class pkgCacheGenerator
 class pkgCacheGenerator

+ 465 - 0
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;
+}
+									/*}}}*/

+ 78 - 0
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

+ 5 - 1
apt-pkg/tagfile.cc

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
 // 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
    Fast scanner for RFC-822 type header information
@@ -11,6 +11,10 @@
    ##################################################################### */
    ##################################################################### */
 									/*}}}*/
 									/*}}}*/
 // Include Files							/*{{{*/
 // Include Files							/*{{{*/
+#ifdef __GNUG__
+#pragma implementation "pkglib/tagfile.h"
+#endif
+
 #include <pkglib/tagfile.h>
 #include <pkglib/tagfile.h>
 #include <pkglib/error.h>
 #include <pkglib/error.h>
 
 

+ 5 - 1
apt-pkg/tagfile.h

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
 // 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
    Fast scanner for RFC-822 type header information
@@ -21,6 +21,10 @@
 #ifndef PKGLIB_TAGFILE_H
 #ifndef PKGLIB_TAGFILE_H
 #define PKGLIB_TAGFILE_H
 #define PKGLIB_TAGFILE_H
 
 
+#ifdef __GNUG__
+#pragma interface "pkglib/tagfile.h"
+#endif 
+
 #include <pkglib/fileutl.h>
 #include <pkglib/fileutl.h>
 
 
 class pkgTagSection
 class pkgTagSection

+ 11 - 7
apt-pkg/version.cc

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
 // 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 
    Version - Version string 
@@ -17,6 +17,10 @@
    ##################################################################### */
    ##################################################################### */
 									/*}}}*/
 									/*}}}*/
 // Include Files							/*{{{*/
 // Include Files							/*{{{*/
+#ifdef __GNUG__
+#pragma implementation "pkglib/version.h"
+#endif 
+
 #include <pkglib/version.h>
 #include <pkglib/version.h>
 #include <pkglib/pkgcache.h>
 #include <pkglib/pkgcache.h>
 
 
@@ -212,32 +216,32 @@ bool pkgCheckDep(const char *DepVer,const char *PkgVer,int Op)
    int Res = pkgVersionCompare(PkgVer,DepVer);
    int Res = pkgVersionCompare(PkgVer,DepVer);
    switch (Op & 0x0F)
    switch (Op & 0x0F)
    {
    {
-      case pkgCache::LessEq:
+      case pkgCache::Dep::LessEq:
       if (Res <= 0)
       if (Res <= 0)
 	 return true;
 	 return true;
       break;
       break;
       
       
-      case pkgCache::GreaterEq:
+      case pkgCache::Dep::GreaterEq:
       if (Res >= 0)
       if (Res >= 0)
 	 return true;
 	 return true;
       break;
       break;
       
       
-      case pkgCache::Less:
+      case pkgCache::Dep::Less:
       if (Res < 0)
       if (Res < 0)
 	 return true;
 	 return true;
       break;
       break;
       
       
-      case pkgCache::Greater:
+      case pkgCache::Dep::Greater:
       if (Res > 0)
       if (Res > 0)
 	 return true;
 	 return true;
       break;
       break;
       
       
-      case pkgCache::Equals:
+      case pkgCache::Dep::Equals:
       if (Res == 0)
       if (Res == 0)
 	 return true;
 	 return true;
       break;
       break;
       
       
-      case pkgCache::NotEquals:
+      case pkgCache::Dep::NotEquals:
       if (Res != 0)
       if (Res != 0)
 	 return true;
 	 return true;
       break;
       break;

+ 5 - 1
apt-pkg/version.h

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
 // 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 
    Version - Version string 
@@ -15,6 +15,10 @@
 #ifndef PKGLIB_VERSION_H
 #ifndef PKGLIB_VERSION_H
 #define PKGLIB_VERSION_H
 #define PKGLIB_VERSION_H
 
 
+#ifdef __GNUG__
+#pragma interface "pkglib/version.h"
+#endif 
+
 #include <string>
 #include <string>
 
 
 class pkgVersion
 class pkgVersion