Browse Source

Join with aliencode
Author: jgg
Date: 2001-02-20 07:03:16 GMT
Join with aliencode

Arch Librarian 19 years ago
parent
commit
b2e465d6d3
100 changed files with 8961 additions and 2445 deletions
  1. 5 1
      AUTHORS
  2. 8 7
      Makefile
  3. 154 0
      apt-inst/contrib/arfile.cc
  4. 68 0
      apt-inst/contrib/arfile.h
  5. 342 0
      apt-inst/contrib/extracttar.cc
  6. 54 0
      apt-inst/contrib/extracttar.h
  7. 30 0
      apt-inst/database.cc
  8. 56 0
      apt-inst/database.h
  9. 262 0
      apt-inst/deb/debfile.cc
  10. 92 0
      apt-inst/deb/debfile.h
  11. 490 0
      apt-inst/deb/dpkgdb.cc
  12. 53 0
      apt-inst/deb/dpkgdb.h
  13. 103 0
      apt-inst/dirstream.cc
  14. 61 0
      apt-inst/dirstream.h
  15. 5 0
      apt-inst/dpkg-diffs.txt
  16. 509 0
      apt-inst/extract.cc
  17. 52 0
      apt-inst/extract.h
  18. 588 0
      apt-inst/filelist.cc
  19. 314 0
      apt-inst/filelist.h
  20. 30 0
      apt-inst/makefile
  21. 82 60
      apt-pkg/acquire-item.cc
  22. 11 9
      apt-pkg/acquire-item.h
  23. 6 4
      apt-pkg/acquire-method.cc
  24. 4 2
      apt-pkg/acquire-method.h
  25. 9 7
      apt-pkg/acquire-worker.cc
  26. 3 3
      apt-pkg/acquire-worker.h
  27. 14 12
      apt-pkg/acquire.cc
  28. 13 12
      apt-pkg/acquire.h
  29. 156 67
      apt-pkg/algorithms.cc
  30. 21 4
      apt-pkg/algorithms.h
  31. 56 34
      apt-pkg/cachefile.cc
  32. 18 13
      apt-pkg/cachefile.h
  33. 31 19
      apt-pkg/cacheiterators.h
  34. 19 9
      apt-pkg/clean.cc
  35. 8 6
      apt-pkg/contrib/cdromutl.cc
  36. 16 14
      apt-pkg/contrib/cmndline.cc
  37. 340 66
      apt-pkg/contrib/configuration.cc
  38. 39 18
      apt-pkg/contrib/configuration.h
  39. 2 2
      apt-pkg/contrib/error.cc
  40. 17 5
      apt-pkg/contrib/error.h
  41. 81 26
      apt-pkg/contrib/fileutl.cc
  42. 5 2
      apt-pkg/contrib/fileutl.h
  43. 2 2
      apt-pkg/contrib/md5.h
  44. 15 8
      apt-pkg/contrib/mmap.cc
  45. 10 4
      apt-pkg/contrib/progress.cc
  46. 66 0
      apt-pkg/contrib/sptr.h
  47. 153 10
      apt-pkg/contrib/strutl.cc
  48. 34 4
      apt-pkg/contrib/strutl.h
  49. 506 0
      apt-pkg/deb/debindexfile.cc
  50. 112 0
      apt-pkg/deb/debindexfile.h
  51. 143 78
      apt-pkg/deb/deblistparser.cc
  52. 22 14
      apt-pkg/deb/deblistparser.h
  53. 20 3
      apt-pkg/deb/debrecords.cc
  54. 7 5
      apt-pkg/deb/debrecords.h
  55. 69 28
      apt-pkg/deb/debsrcrecords.cc
  56. 14 10
      apt-pkg/deb/debsrcrecords.h
  57. 197 0
      apt-pkg/deb/debsystem.cc
  58. 41 0
      apt-pkg/deb/debsystem.h
  59. 266 0
      apt-pkg/deb/debversion.cc
  60. 72 0
      apt-pkg/deb/debversion.h
  61. 0 119
      apt-pkg/deb/dpkginit.cc
  62. 0 34
      apt-pkg/deb/dpkginit.h
  63. 136 26
      apt-pkg/deb/dpkgpm.cc
  64. 5 3
      apt-pkg/deb/dpkgpm.h
  65. 164 91
      apt-pkg/depcache.cc
  66. 48 24
      apt-pkg/depcache.h
  67. 77 0
      apt-pkg/indexfile.cc
  68. 80 0
      apt-pkg/indexfile.h
  69. 82 23
      apt-pkg/init.cc
  70. 25 3
      apt-pkg/init.h
  71. 24 19
      apt-pkg/makefile
  72. 74 45
      apt-pkg/orderlist.cc
  73. 6 15
      apt-pkg/orderlist.h
  74. 29 27
      apt-pkg/packagemanager.cc
  75. 8 17
      apt-pkg/packagemanager.h
  76. 151 94
      apt-pkg/pkgcache.cc
  77. 47 17
      apt-pkg/pkgcache.h
  78. 249 439
      apt-pkg/pkgcachegen.cc
  79. 25 16
      apt-pkg/pkgcachegen.h
  80. 17 28
      apt-pkg/pkgrecords.cc
  81. 10 17
      apt-pkg/pkgrecords.h
  82. 45 0
      apt-pkg/pkgsystem.cc
  83. 95 0
      apt-pkg/pkgsystem.h
  84. 275 0
      apt-pkg/policy.cc
  85. 83 0
      apt-pkg/policy.h
  86. 127 297
      apt-pkg/sourcelist.cc
  87. 35 26
      apt-pkg/sourcelist.h
  88. 34 34
      apt-pkg/srcrecords.cc
  89. 32 15
      apt-pkg/srcrecords.h
  90. 259 23
      apt-pkg/tagfile.cc
  91. 34 15
      apt-pkg/tagfile.h
  92. 17 244
      apt-pkg/version.cc
  93. 58 11
      apt-pkg/version.h
  94. 210 0
      apt-pkg/versionmatch.cc
  95. 69 0
      apt-pkg/versionmatch.h
  96. 1 0
      buildlib/apti18n.h.in
  97. 22 32
      buildlib/archtable
  98. 327 112
      buildlib/config.guess
  99. 5 11
      buildlib/config.h.in
  100. 0 0
      buildlib/config.sub

+ 5 - 1
AUTHORS

@@ -6,16 +6,20 @@ CVS:jgg Jason Gunthorpe <jgg@debian.org>
 CVS:che Ben Gertzfield <che@debian.org>
 - Packaging and Releases
 
+CVS:bod Brendan O'Dea <bod@debian.org>
+- Perl Bindings
+
 Past Contributures:
 
 Brian White <bcwhite@verisim.com> - Project originator
 Tom Lees <tom@lpsg.demon.co.uk> - DPKG documentation and ideas
 Behan Webster <behanw@verisim.com> - Original GUI design
 Scott Ellis <storm@gate.net> - Original packaging and beta releases
-Branden Branden Robinson <branden@purdue.edu> - Man Page Documentation
+Branden Robinson <branden@purdue.edu> - Man Page Documentation
 Manoj Srivastava <srivasta@datasync.com> - 1st Generation FTP method and
                                            dselect setup script
 Adam Heath <doogie@debian.org> - 2nd Generation FTP method author
+Ben Collins <bcollins@debian.org> - Initial RSH method
 Many other bug reports through the Debian Bug system
 
 NOTE: The ChangeLog generator will parse for names and email addresses. The

+ 8 - 7
Makefile

@@ -6,17 +6,17 @@ ifndef NOISY
 .SILENT:
 endif
 
+.PHONY: default
+default: startup all
+
 .PHONY: headers library clean veryclean all binary program doc
-all headers library clean veryclean binary program doc:
+all headers library clean veryclean binary program doc dirs:
 	$(MAKE) -C apt-pkg $@
+	$(MAKE) -C apt-inst $@
 	$(MAKE) -C methods $@
-#	$(MAKE) -C methods/ftp $@
 	$(MAKE) -C cmdline $@
+	$(MAKE) -C ftparchive $@
 	$(MAKE) -C dselect $@
-ifdef GUI	
-	$(MAKE) -C deity $@
-	$(MAKE) -C gui $@
-endif
 	$(MAKE) -C doc $@
 
 # Some very common aliases
@@ -25,8 +25,9 @@ maintainer-clean dist-clean distclean pristine sanity: veryclean
 
 # The startup target builds the necessary configure scripts. It should
 # be used after a CVS checkout.
-CONVERTED=environment.mak include/config.h makefile
+CONVERTED=environment.mak include/config.h include/apti18n.h makefile
 include buildlib/configure.mak
 $(BUILDDIR)/include/config.h: buildlib/config.h.in
+$(BUILDDIR)/include/apti18n.h: buildlib/apti18n.h.in
 $(BUILDDIR)/environment.mak: buildlib/environment.mak.in
 $(BUILDDIR)/makefile: buildlib/makefile.in

+ 154 - 0
apt-inst/contrib/arfile.cc

@@ -0,0 +1,154 @@
+// -*- mode: cpp; mode: fold -*-
+// Description								/*{{{*/
+// $Id: arfile.cc,v 1.2 2001/02/20 07:03:16 jgg Exp $
+/* ######################################################################
+
+   AR File - Handle an 'AR' archive
+   
+   AR Archives have plain text headers at the start of each file
+   section. The headers are aligned on a 2 byte boundry.
+   
+   Information about the structure of AR files can be found in ar(5)
+   on a BSD system, or in the binutils source.
+
+   ##################################################################### */
+									/*}}}*/
+// Include Files							/*{{{*/
+#ifdef __GNUG__
+#pragma implementation "apt-pkg/arfile.h"
+#endif
+#include <apt-pkg/arfile.h>
+#include <apt-pkg/strutl.h>
+#include <apt-pkg/error.h>
+
+#include <stdlib.h>
+									/*}}}*/
+
+struct ARArchive::MemberHeader
+{
+   char Name[16];
+   char MTime[12];
+   char UID[6];
+   char GID[6];
+   char Mode[8];
+   char Size[10];
+   char Magic[2];
+};
+
+// ARArchive::ARArchive - Constructor					/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+ARArchive::ARArchive(FileFd &File) : List(0), File(File)
+{
+   LoadHeaders();
+}
+									/*}}}*/
+// ARArchive::~ARArchive - Destructor					/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+ARArchive::~ARArchive()
+{
+   while (List != 0)
+   {
+      Member *Tmp = List;
+      List = List->Next;
+      delete Tmp;
+   }   
+}
+									/*}}}*/
+// ARArchive::LoadHeaders - Load the headers from each file		/*{{{*/
+// ---------------------------------------------------------------------
+/* AR files are structured with a 8 byte magic string followed by a 60
+   byte plain text header then the file data, another header, data, etc */
+bool ARArchive::LoadHeaders()
+{
+   signed long Left = File.Size();
+   
+   // Check the magic byte
+   char Magic[8];
+   if (File.Read(Magic,sizeof(Magic)) == false)
+      return false;
+   if (memcmp(Magic,"!<arch>\012",sizeof(Magic)) != 0)
+      return _error->Error("Invalid archive signature");
+   Left -= sizeof(Magic);
+   
+   // Read the member list
+   while (Left > 0)
+   {
+      MemberHeader Head;
+      if (File.Read(&Head,sizeof(Head)) == false)
+	 return _error->Error("Error reading archive member header");
+      Left -= sizeof(Head);
+
+      // Convert all of the integer members
+      Member *Memb = new Member();
+      if (StrToNum(Head.MTime,Memb->MTime,sizeof(Head.MTime)) == false ||
+	  StrToNum(Head.UID,Memb->UID,sizeof(Head.UID)) == false ||
+	  StrToNum(Head.GID,Memb->GID,sizeof(Head.GID)) == false ||
+	  StrToNum(Head.Mode,Memb->Mode,sizeof(Head.Mode),8) == false ||
+	  StrToNum(Head.Size,Memb->Size,sizeof(Head.Size)) == false)
+      {
+	 delete Memb;
+	 return _error->Error("Invalid archive member header");
+      }
+	 
+      // Check for an extra long name string
+      if (memcmp(Head.Name,"#1/",3) == 0)
+      {
+	 char S[300];
+	 unsigned long Len;
+	 if (StrToNum(Head.Name+3,Len,sizeof(Head.Size)-3) == false ||
+	     Len >= strlen(S))
+	 {
+	    delete Memb;
+	    return _error->Error("Invalid archive member header");
+	 }
+	 if (File.Read(S,Len) == false)
+	    return false;
+	 S[Len] = 0;
+	 Memb->Name = S;
+	 Memb->Size -= Len;
+	 Left -= Len;
+      }
+      else
+      {
+	 unsigned int I = sizeof(Head.Name) - 1;
+	 for (; Head.Name[I] == ' '; I--);
+	 Memb->Name = string(Head.Name,0,I+1);
+      }
+
+      // Account for the AR header alignment 
+      unsigned Skip = Memb->Size % 2;
+      
+      // Add it to the list
+      Memb->Next = List;
+      List = Memb;
+      Memb->Start = File.Tell();
+      if (File.Skip(Memb->Size + Skip) == false)
+	 return false;
+      if (Left < (signed)(Memb->Size + Skip))
+	 return _error->Error("Archive is too short");
+      Left -= Memb->Size + Skip;
+   }   
+   if (Left != 0)
+      return _error->Error("Failed to read the archive headers");
+   
+   return true;
+}
+									/*}}}*/
+// ARArchive::FindMember - Find a name in the member list		/*{{{*/
+// ---------------------------------------------------------------------
+/* Find a member with the given name */
+const ARArchive::Member *ARArchive::FindMember(const char *Name) const
+{
+   const Member *Res = List;
+   while (Res != 0)
+   {
+      if (Res->Name == Name)
+	 return Res;
+      Res = Res->Next;
+   }
+   
+   return 0;
+}
+									/*}}}*/

+ 68 - 0
apt-inst/contrib/arfile.h

@@ -0,0 +1,68 @@
+// -*- mode: cpp; mode: fold -*-
+// Description								/*{{{*/
+// $Id: arfile.h,v 1.2 2001/02/20 07:03:16 jgg Exp $
+/* ######################################################################
+
+   AR File - Handle an 'AR' archive
+   
+   This is a reader for the usual 4.4 BSD AR format. It allows raw
+   stream access to a single member at a time. Basically all this class
+   provides is header parsing and verification. It is up to the client
+   to correctly make use of the stream start/stop points.
+   
+   ##################################################################### */
+									/*}}}*/
+#ifndef PKGLIB_ARFILE_H
+#define PKGLIB_ARFILE_H
+
+#ifdef __GNUG__
+#pragma interface "apt-pkg/arfile.h"
+#endif
+
+#include <string>
+#include <apt-pkg/fileutl.h>
+
+class ARArchive
+{
+   struct MemberHeader;
+   public:
+   struct Member;
+   
+   protected:
+
+   // Linked list of members
+   Member *List;
+   
+   bool LoadHeaders();
+
+   public:
+   
+   // The stream file
+   FileFd &File;
+
+   // Locate a member by name
+   const Member *FindMember(const char *Name) const;
+   
+   ARArchive(FileFd &File);
+   ~ARArchive();
+};
+
+// A member of the archive
+struct ARArchive::Member
+{
+   // Fields from the header
+   string Name;
+   unsigned long MTime;
+   unsigned long UID;
+   unsigned long GID;
+   unsigned long Mode;
+   unsigned long Size;
+   
+   // Location of the data.
+   unsigned long Start;
+   Member *Next;
+   
+   Member() : Start(0), Next(0) {};
+};
+
+#endif

+ 342 - 0
apt-inst/contrib/extracttar.cc

@@ -0,0 +1,342 @@
+// -*- mode: cpp; mode: fold -*-
+// Description								/*{{{*/
+// $Id: extracttar.cc,v 1.2 2001/02/20 07:03:17 jgg Exp $
+/* ######################################################################
+
+   Extract a Tar - Tar Extractor
+
+   Some performance measurements showed that zlib performed quite poorly
+   in comparision to a forked gzip process. This tar extractor makes use
+   of the fact that dup'd file descriptors have the same seek pointer
+   and that gzip will not read past the end of a compressed stream, 
+   even if there is more data. We use the dup property to track extraction
+   progress and the gzip feature to just feed gzip a fd in the middle
+   of an AR file. 
+   
+   ##################################################################### */
+									/*}}}*/
+// Include Files							/*{{{*/
+#ifdef __GNUG__
+#pragma implementation "apt-pkg/extracttar.h"
+#endif
+#include <apt-pkg/extracttar.h>
+
+#include <apt-pkg/error.h>
+#include <apt-pkg/strutl.h>
+#include <apt-pkg/configuration.h>
+#include <system.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <fcntl.h>
+									/*}}}*/
+
+// The on disk header for a tar file.
+struct ExtractTar::TarHeader
+{
+   char Name[100];
+   char Mode[8];
+   char UserID[8];
+   char GroupID[8];
+   char Size[12];
+   char MTime[12];
+   char Checksum[8];
+   char LinkFlag;
+   char LinkName[100];
+   char MagicNumber[8];
+   char UserName[32];
+   char GroupName[32];
+   char Major[8];
+   char Minor[8];      
+};
+   
+// ExtractTar::ExtractTar - Constructor					/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+ExtractTar::ExtractTar(FileFd &Fd,unsigned long Max) : File(Fd), 
+                         MaxInSize(Max)
+
+{
+   GZPid = -1;
+   InFd = -1;
+   Eof = false;
+}
+									/*}}}*/
+// ExtractTar::ExtractTar - Destructor					/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+ExtractTar::~ExtractTar()
+{
+   Done(false);
+}
+									/*}}}*/
+// ExtractTar::Done - Reap the gzip sub process				/*{{{*/
+// ---------------------------------------------------------------------
+/* If the force flag is given then error messages are suppressed - this
+   means we hit the end of the tar file but there was still gzip data. */
+bool ExtractTar::Done(bool Force)
+{
+   InFd.Close();
+   if (GZPid <= 0)
+      return true;
+
+   /* If there is a pending error then we are cleaning up gzip and are
+      not interested in it's failures */
+   if (_error->PendingError() == true)
+      Force = true;
+   
+   // Make sure we clean it up!
+   kill(GZPid,SIGINT);
+   if (ExecWait(GZPid,_config->Find("dir::bin::gzip","/bin/gzip").c_str(),
+		Force) == false)
+   {
+      GZPid = -1;
+      return Force;
+   }
+   
+   GZPid = -1;
+   return true;
+}
+									/*}}}*/
+// ExtractTar::StartGzip - Startup gzip					/*{{{*/
+// ---------------------------------------------------------------------
+/* This creates a gzip sub process that has its input as the file itself.
+   If this tar file is embedded into something like an ar file then 
+   gzip will efficiently ignore the extra bits. */
+bool ExtractTar::StartGzip()
+{
+   int Pipes[2];
+   if (pipe(Pipes) != 0)
+      return _error->Errno("pipe","Failed to create pipes");
+   
+   // Fork off the process
+   GZPid = ExecFork();
+
+   // Spawn the subprocess
+   if (GZPid == 0)
+   {
+      // Setup the FDs
+      dup2(Pipes[1],STDOUT_FILENO);
+      dup2(File.Fd(),STDIN_FILENO);
+      int Fd = open("/dev/null",O_RDWR);
+      if (Fd == -1)
+	 _exit(101);
+      dup2(Fd,STDERR_FILENO);
+      close(Fd);
+      SetCloseExec(STDOUT_FILENO,false);
+      SetCloseExec(STDIN_FILENO,false);      
+      SetCloseExec(STDERR_FILENO,false);
+      
+      const char *Args[3];
+      Args[0] = _config->Find("dir::bin::gzip","/bin/gzip").c_str();
+      Args[1] = "-d";
+      Args[2] = 0;
+      execv(Args[0],(char **)Args);
+      cerr << "Failed to exec gzip " << Args[0] << endl;
+      _exit(100);
+   }
+
+   // Fix up our FDs
+   InFd.Fd(Pipes[0]);
+   close(Pipes[1]);
+   return true;
+}
+									/*}}}*/
+// ExtractTar::Go - Perform extraction					/*{{{*/
+// ---------------------------------------------------------------------
+/* This reads each 512 byte block from the archive and extracts the header
+   information into the Item structure. Then it resolves the UID/GID and
+   invokes the correct processing function. */
+bool ExtractTar::Go(pkgDirStream &Stream)
+{   
+   if (StartGzip() == false)
+      return false;
+   
+   // Loop over all blocks
+   string LastLongLink;
+   string LastLongName;
+   while (1)
+   {
+      bool BadRecord = false;      
+      unsigned char Block[512];      
+      if (InFd.Read(Block,sizeof(Block),true) == false)
+	 return false;
+      
+      if (InFd.Eof() == true)
+	 break;
+
+      // Get the checksum
+      TarHeader *Tar = (TarHeader *)Block;
+      unsigned long CheckSum;
+      if (StrToNum(Tar->Checksum,CheckSum,sizeof(Tar->Checksum),8) == false)
+	 return _error->Error("Corrupted archive");
+      
+      /* Compute the checksum field. The actual checksum is blanked out
+         with spaces so it is not included in the computation */
+      unsigned long NewSum = 0;
+      memset(Tar->Checksum,' ',sizeof(Tar->Checksum));
+      for (int I = 0; I != sizeof(Block); I++)
+	 NewSum += Block[I];
+      
+      /* Check for a block of nulls - in this case we kill gzip, GNU tar
+       	 does this.. */
+      if (NewSum == ' '*sizeof(Tar->Checksum))
+	 return Done(true);
+      
+      if (NewSum != CheckSum)
+	 return _error->Error("Tar Checksum failed, archive corrupted");
+   
+      // Decode all of the fields
+      pkgDirStream::Item Itm;
+      unsigned long UID;
+      unsigned long GID;
+      if (StrToNum(Tar->Mode,Itm.Mode,sizeof(Tar->Mode),8) == false ||
+	  StrToNum(Tar->UserID,UID,sizeof(Tar->UserID),8) == false ||
+	  StrToNum(Tar->GroupID,GID,sizeof(Tar->GroupID),8) == false ||
+	  StrToNum(Tar->Size,Itm.Size,sizeof(Tar->Size),8) == false ||
+	  StrToNum(Tar->MTime,Itm.MTime,sizeof(Tar->MTime),8) == false ||
+	  StrToNum(Tar->Major,Itm.Major,sizeof(Tar->Major),8) == false ||
+	  StrToNum(Tar->Minor,Itm.Minor,sizeof(Tar->Minor),8) == false)
+	 return _error->Error("Corrupted archive");
+      
+      // Grab the filename
+      if (LastLongName.empty() == false)
+	 Itm.Name = (char *)LastLongName.c_str();
+      else
+      {
+	 Tar->Name[sizeof(Tar->Name)] = 0;
+	 Itm.Name = Tar->Name;
+      }      
+      if (Itm.Name[0] == '.' && Itm.Name[1] == '/' && Itm.Name[2] != 0)
+	 Itm.Name += 2;
+      
+      // Grab the link target
+      Tar->Name[sizeof(Tar->LinkName)] = 0;
+      Itm.LinkTarget = Tar->LinkName;
+
+      if (LastLongLink.empty() == false)
+	 Itm.LinkTarget = (char *)LastLongLink.c_str();
+      
+      // Convert the type over
+      switch (Tar->LinkFlag)
+      {
+	 case NormalFile0:
+	 case NormalFile:
+	 Itm.Type = pkgDirStream::Item::File;
+	 break;
+	 
+	 case HardLink:
+	 Itm.Type = pkgDirStream::Item::HardLink;
+	 break;
+	 
+	 case SymbolicLink:
+	 Itm.Type = pkgDirStream::Item::SymbolicLink;
+	 break;
+	 
+	 case CharacterDevice:
+	 Itm.Type = pkgDirStream::Item::CharDevice;
+	 break;
+	    
+	 case BlockDevice:
+	 Itm.Type = pkgDirStream::Item::BlockDevice;
+	 break;
+	 
+	 case Directory:
+	 Itm.Type = pkgDirStream::Item::Directory;
+	 break;
+	 
+	 case FIFO:
+	 Itm.Type = pkgDirStream::Item::FIFO;
+	 break;
+
+	 case GNU_LongLink:
+	 {
+	    unsigned long Length = Itm.Size;
+	    unsigned char Block[512];
+	    while (Length > 0)
+	    {
+	       if (InFd.Read(Block,sizeof(Block),true) == false)
+		  return false;
+	       if (Length <= sizeof(Block))
+	       {
+		  LastLongLink.append(Block,Block+sizeof(Block));
+		  break;
+	       }	       
+	       LastLongLink.append(Block,Block+sizeof(Block));
+	       Length -= sizeof(Block);
+	    }
+	    continue;
+	 }
+	 
+	 case GNU_LongName:
+	 {
+	    unsigned long Length = Itm.Size;
+	    unsigned char Block[512];
+	    while (Length > 0)
+	    {
+	       if (InFd.Read(Block,sizeof(Block),true) == false)
+		  return false;
+	       if (Length < sizeof(Block))
+	       {
+		  LastLongName.append(Block,Block+sizeof(Block));
+		  break;
+	       }	       
+	       LastLongName.append(Block,Block+sizeof(Block));
+	       Length -= sizeof(Block);
+	    }
+	    continue;
+	 }
+	 
+	 default:
+	 BadRecord = true;
+	 _error->Warning("Unkown TAR header type %u, member %s",(unsigned)Tar->LinkFlag,Tar->Name);
+	 break;
+      }
+      
+      int Fd = -1;
+      if (BadRecord == false)
+	 if (Stream.DoItem(Itm,Fd) == false)
+	    return false;
+      
+      // Copy the file over the FD
+      unsigned long Size = Itm.Size;
+      while (Size != 0)
+      {
+	 unsigned char Junk[32*1024];
+	 unsigned long Read = MIN(Size,sizeof(Junk));
+	 if (InFd.Read(Junk,((Read+511)/512)*512) == false)
+	    return false;
+	 
+	 if (BadRecord == false)
+	 {
+	    if (Fd > 0)
+	    {
+	       if (write(Fd,Junk,Read) != (signed)Read)
+		  return Stream.Fail(Itm,Fd);
+	    }
+	    else
+	    {
+	       /* An Fd of -2 means to send to a special processing
+		  function */
+	       if (Fd == -2)
+		  if (Stream.Process(Itm,Junk,Read,Itm.Size - Size) == false)
+		     return Stream.Fail(Itm,Fd);
+	    }
+	 }
+	 
+	 Size -= Read;
+      }
+      
+      // And finish up
+      if (Itm.Size != 0 && BadRecord == false)
+	 if (Stream.FinishedFile(Itm,Fd) == false)
+	    return false;
+      
+      LastLongName.erase();
+      LastLongLink.erase();
+   }
+   
+   return Done(false);
+}
+									/*}}}*/

+ 54 - 0
apt-inst/contrib/extracttar.h

@@ -0,0 +1,54 @@
+// -*- mode: cpp; mode: fold -*-
+// Description								/*{{{*/
+// $Id: extracttar.h,v 1.2 2001/02/20 07:03:17 jgg Exp $
+/* ######################################################################
+
+   Extract a Tar - Tar Extractor
+   
+   The tar extractor takes an ordinary gzip compressed tar stream from 
+   the given file and explodes it, passing the individual items to the
+   given Directory Stream for processing.
+   
+   ##################################################################### */
+									/*}}}*/
+#ifndef PKGLIB_EXTRACTTAR_H
+#define PKGLIB_EXTRACTTAR_H
+
+#ifdef __GNUG__
+#pragma interface "apt-pkg/extracttar.h"
+#endif
+
+#include <apt-pkg/fileutl.h>
+#include <apt-pkg/dirstream.h>
+
+class ExtractTar
+{
+   protected:
+   
+   struct TarHeader;
+   
+   // The varios types items can be
+   enum ItemType {NormalFile0 = '\0',NormalFile = '0',HardLink = '1',
+                  SymbolicLink = '2',CharacterDevice = '3',
+                  BlockDevice = '4',Directory = '5',FIFO = '6',
+                  GNU_LongLink = 'K',GNU_LongName = 'L'};
+
+   FileFd &File;
+   unsigned long MaxInSize;
+   int GZPid;
+   FileFd InFd;
+   bool Eof;
+   
+   // Fork and reap gzip
+   bool StartGzip();
+   bool Done(bool Force);
+   
+   public:
+
+   bool Go(pkgDirStream &Stream);
+   
+   ExtractTar(FileFd &Fd,unsigned long Max);
+   virtual ~ExtractTar();
+};
+
+#endif

+ 30 - 0
apt-inst/database.cc

@@ -0,0 +1,30 @@
+// -*- mode: cpp; mode: fold -*-
+// Description								/*{{{*/
+// $Id: database.cc,v 1.2 2001/02/20 07:03:16 jgg Exp $
+/* ######################################################################
+
+   Data Base Abstraction
+   
+   ##################################################################### */
+									/*}}}*/
+// Include Files							/*{{{*/
+#ifdef __GNUG__
+#pragma implementation "apt-pkg/database.h"
+#endif
+
+#include <apt-pkg/database.h>
+									/*}}}*/
+
+// DataBase::GetMetaTmp - Get the temp dir				/*{{{*/
+// ---------------------------------------------------------------------
+/* This re-initializes the meta temporary directory if it hasn't yet 
+   been inited for this cycle. The flag is the emptyness of MetaDir */
+bool pkgDataBase::GetMetaTmp(string &Dir)
+{
+   if (MetaDir.empty() == true)
+      if (InitMetaTmp(MetaDir) == false)
+	 return false;
+   Dir = MetaDir;
+   return true;
+}
+									/*}}}*/

+ 56 - 0
apt-inst/database.h

@@ -0,0 +1,56 @@
+// -*- mode: cpp; mode: fold -*-
+// Description								/*{{{*/
+// $Id: database.h,v 1.2 2001/02/20 07:03:16 jgg Exp $
+/* ######################################################################
+
+   Data Base Abstraction
+   
+   This class provides a simple interface to an abstract notion of a 
+   database directory for storing state information about the system.
+
+   The 'Meta' information for a package is the control information and
+   setup scripts stored inside the archive. GetMetaTmp returns the name of
+   a directory that is used to store named files containing the control
+   information. 
+   
+   The File Listing is the database of installed files. It is loaded 
+   into the memory/persistent cache structure by the ReadFileList method.  
+   
+   ##################################################################### */
+									/*}}}*/
+#ifndef PKGLIB_DATABASE_H
+#define PKGLIB_DATABASE_H
+
+#ifdef __GNUG__
+#pragma interface "apt-pkg/database.h"
+#endif
+
+#include <apt-pkg/filelist.h>
+#include <apt-pkg/pkgcachegen.h>
+
+class pkgDataBase
+{
+   protected:
+   
+   pkgCacheGenerator *Cache;
+   pkgFLCache *FList;
+   string MetaDir;
+   virtual bool InitMetaTmp(string &Dir) = 0;
+   
+   public:
+
+   // Some manipulators for the cache and generator
+   inline pkgCache &GetCache() {return Cache->GetCache();};
+   inline pkgFLCache &GetFLCache() {return *FList;};
+   inline pkgCacheGenerator &GetGenerator() {return *Cache;};
+   
+   bool GetMetaTmp(string &Dir);
+   virtual bool ReadyFileList(OpProgress &Progress) = 0;
+   virtual bool ReadyPkgCache(OpProgress &Progress) = 0;
+   virtual bool LoadChanges() = 0;
+
+   pkgDataBase() : Cache(0), FList(0) {};
+   virtual ~pkgDataBase() {delete Cache; delete FList;};
+};
+
+#endif

+ 262 - 0
apt-inst/deb/debfile.cc

@@ -0,0 +1,262 @@
+// -*- mode: cpp; mode: fold -*-
+// Description								/*{{{*/
+// $Id: debfile.cc,v 1.2 2001/02/20 07:03:17 jgg Exp $
+/* ######################################################################
+
+   Debian Archive File (.deb)
+   
+   .DEB archives are AR files containing two tars and an empty marker
+   member called 'debian-binary'. The two tars contain the meta data and
+   the actual archive contents. Thus this class is a very simple wrapper
+   around ar/tar to simply extract the right tar files.
+   
+   It also uses the deb package list parser to parse the control file 
+   into the cache.
+   
+   ##################################################################### */
+									/*}}}*/
+// Include Files							/*{{{*/
+#ifdef __GNUG__
+#pragma implementation "apt-pkg/debfile.h"
+#endif
+
+#include <apt-pkg/debfile.h>
+#include <apt-pkg/extracttar.h>
+#include <apt-pkg/error.h>
+#include <apt-pkg/deblistparser.h>
+
+#include <sys/stat.h>
+#include <unistd.h>
+									/*}}}*/
+
+// DebFile::debDebFile - Constructor					/*{{{*/
+// ---------------------------------------------------------------------
+/* Open the AR file and check for consistency */
+debDebFile::debDebFile(FileFd &File) : File(File), AR(File)
+{
+   if (_error->PendingError() == true)
+      return;
+   
+   // Check the members for validity
+   if (CheckMember("debian-binary") == false ||
+       CheckMember("control.tar.gz") == false ||
+       CheckMember("data.tar.gz") == false)
+      return;
+}
+									/*}}}*/
+// DebFile::CheckMember - Check if a named member is in the archive	/*{{{*/
+// ---------------------------------------------------------------------
+/* This is used to check for a correct deb and to give nicer error messages
+   for people playing around. */
+bool debDebFile::CheckMember(const char *Name)
+{
+   if (AR.FindMember(Name) == 0)
+      return _error->Error("This is not a valid DEB archive, missing '%s' member",Name);
+   return true;
+}
+									/*}}}*/
+// DebFile::GotoMember - Jump to a Member				/*{{{*/
+// ---------------------------------------------------------------------
+/* Jump in the file to the start of a named member and return the information
+   about that member. The caller can then read from the file up to the 
+   returned size. Note, since this relies on the file position this is
+   a destructive operation, it also changes the last returned Member
+   structure - so don't nest them! */
+const ARArchive::Member *debDebFile::GotoMember(const char *Name)
+{
+   // Get the archive member and positition the file
+   const ARArchive::Member *Member = AR.FindMember(Name);
+   if (Member == 0)
+   {
+      _error->Error("Internal Error, could not locate member %s",Name);
+      return 0;
+   }
+   if (File.Seek(Member->Start) == false)
+      return 0;
+      
+   return Member;
+}
+									/*}}}*/
+// DebFile::ExtractControl - Extract Control information		/*{{{*/
+// ---------------------------------------------------------------------
+/* Extract the control information into the Database's temporary 
+   directory. */
+bool debDebFile::ExtractControl(pkgDataBase &DB)
+{
+   // Get the archive member and positition the file
+   const ARArchive::Member *Member = GotoMember("control.tar.gz");
+   if (Member == 0)
+      return false;
+      
+   // Prepare Tar
+   ControlExtract Extract;
+   ExtractTar Tar(File,Member->Size);
+   if (_error->PendingError() == true)
+      return false;
+   
+   // Get into the temporary directory
+   string Cwd = SafeGetCWD();
+   string Tmp;
+   if (DB.GetMetaTmp(Tmp) == false)
+      return false;
+   if (chdir(Tmp.c_str()) != 0)
+      return _error->Errno("chdir","Couldn't change to %s",Tmp.c_str());
+   
+   // Do extraction
+   if (Tar.Go(Extract) == false)
+      return false;
+   
+   // Switch out of the tmp directory.
+   if (chdir(Cwd.c_str()) != 0)
+      chdir("/");
+   
+   return true;
+}
+									/*}}}*/
+// DebFile::ExtractArchive - Extract the archive data itself		/*{{{*/
+// ---------------------------------------------------------------------
+/* Simple wrapper around tar.. */
+bool debDebFile::ExtractArchive(pkgDirStream &Stream)
+{
+   // Get the archive member and positition the file 
+   const ARArchive::Member *Member = AR.FindMember("data.tar.gz");
+   if (Member == 0)
+      return _error->Error("Internal Error, could not locate member");   
+   if (File.Seek(Member->Start) == false)
+      return false;
+      
+   // Prepare Tar
+   ExtractTar Tar(File,Member->Size);
+   if (_error->PendingError() == true)
+      return false;
+   return Tar.Go(Stream);
+}
+									/*}}}*/
+// DebFile::MergeControl - Merge the control information		/*{{{*/
+// ---------------------------------------------------------------------
+/* This reads the extracted control file into the cache and returns the
+   version that was parsed. All this really does is select the correct
+   parser and correct file to parse. */
+pkgCache::VerIterator debDebFile::MergeControl(pkgDataBase &DB)
+{
+   // Open the control file
+   string Tmp;
+   if (DB.GetMetaTmp(Tmp) == false)
+      return pkgCache::VerIterator(DB.GetCache());
+   FileFd Fd(Tmp + "control",FileFd::ReadOnly);
+   if (_error->PendingError() == true)
+      return pkgCache::VerIterator(DB.GetCache());
+   
+   // Parse it
+   debListParser Parse(&Fd);
+   pkgCache::VerIterator Ver(DB.GetCache());
+   if (DB.GetGenerator().MergeList(Parse,&Ver) == false)
+      return pkgCache::VerIterator(DB.GetCache());
+   
+   if (Ver.end() == true)
+      _error->Error("Failed to locate a valid control file");
+   return Ver;
+}
+									/*}}}*/
+
+// DebFile::ControlExtract::DoItem - Control Tar Extraction		/*{{{*/
+// ---------------------------------------------------------------------
+/* This directory stream handler for the control tar handles extracting
+   it into the temporary meta directory. It only extracts files, it does
+   not create directories, links or anything else. */
+bool debDebFile::ControlExtract::DoItem(Item &Itm,int &Fd)
+{
+   if (Itm.Type != Item::File)
+      return true;
+   
+   /* Cleanse the file name, prevent people from trying to unpack into
+      absolute paths, .., etc */
+   for (char *I = Itm.Name; *I != 0; I++)
+      if (*I == '/')
+	 *I = '_';
+
+   /* Force the ownership to be root and ensure correct permissions, 
+      go-w, the rest are left untouched */
+   Itm.UID = 0;
+   Itm.GID = 0;
+   Itm.Mode &= ~(S_IWGRP | S_IWOTH);
+   
+   return pkgDirStream::DoItem(Itm,Fd);
+}
+									/*}}}*/
+
+// MemControlExtract::DoItem - Check if it is the control file		/*{{{*/
+// ---------------------------------------------------------------------
+/* This sets up to extract the control block member file into a memory 
+   block of just the right size. All other files go into the bit bucket. */
+bool debDebFile::MemControlExtract::DoItem(Item &Itm,int &Fd)
+{
+   // At the control file, allocate buffer memory.
+   if (Member == Itm.Name)
+   {
+      delete [] Control;
+      Control = new char[Itm.Size+2];
+      IsControl = true;
+      Fd = -2; // Signal to pass to Process
+      Length = Itm.Size;
+   }   
+   else
+      IsControl = false;
+   
+   return true;
+}
+									/*}}}*/
+// MemControlExtract::Process - Process extracting the control file	/*{{{*/
+// ---------------------------------------------------------------------
+/* Just memcopy the block from the tar extractor and put it in the right
+   place in the pre-allocated memory block. */
+bool debDebFile::MemControlExtract::Process(Item &Itm,const unsigned char *Data,
+			     unsigned long Size,unsigned long Pos)
+{
+   memcpy(Control + Pos, Data,Size);
+   return true;
+}
+									/*}}}*/
+// MemControlExtract::Read - Read the control information from the deb	/*{{{*/
+// ---------------------------------------------------------------------
+/* This uses the internal tar extractor to fetch the control file, and then
+   it parses it into a tag section parser. */
+bool debDebFile::MemControlExtract::Read(debDebFile &Deb)
+{
+   // Get the archive member and positition the file 
+   const ARArchive::Member *Member = Deb.GotoMember("control.tar.gz");
+   if (Member == 0)
+      return false;
+
+   // Extract it.
+   ExtractTar Tar(Deb.GetFile(),Member->Size);
+   if (Tar.Go(*this) == false)
+      return false;
+
+   if (Control == 0)
+      return true;
+   
+   Control[Length] = '\n';
+   Control[Length+1] = '\n';
+   if (Section.Scan(Control,Length+2) == false)
+      return _error->Error("Unparsible control file");
+   return true;
+}
+									/*}}}*/
+// MemControlExtract::TakeControl - Parse a memory block		/*{{{*/
+// ---------------------------------------------------------------------
+/* The given memory block is loaded into the parser and parsed as a control
+   record. */
+bool debDebFile::MemControlExtract::TakeControl(const void *Data,unsigned long Size)
+{
+   delete [] Control;
+   Control = new char[Size+2];
+   Length = Size;
+   memcpy(Control,Data,Size);
+   
+   Control[Length] = '\n';
+   Control[Length+1] = '\n';
+   return Section.Scan(Control,Length+2);
+}
+									/*}}}*/
+

+ 92 - 0
apt-inst/deb/debfile.h

@@ -0,0 +1,92 @@
+// -*- mode: cpp; mode: fold -*-
+// Description								/*{{{*/
+// $Id: debfile.h,v 1.2 2001/02/20 07:03:17 jgg Exp $
+/* ######################################################################
+
+   Debian Archive File (.deb)
+
+   This Class handles all the operations performed directly on .deb 
+   files. It makes use of the AR and TAR classes to give the necessary
+   external interface.
+   
+   There are only two things that can be done with a raw package, 
+   extract it's control information and extract the contents itself. 
+
+   This should probably subclass an as-yet unwritten super class to
+   produce a generic archive mechanism.
+  
+   The memory control file extractor is useful to extract a single file
+   into memory from the control.tar.gz
+   
+   ##################################################################### */
+									/*}}}*/
+#ifndef PKGLIB_DEBFILE_H
+#define PKGLIB_DEBFILE_H
+
+#ifdef __GNUG__
+#pragma interface "apt-pkg/debfile.h"
+#endif
+
+#include <apt-pkg/arfile.h>
+#include <apt-pkg/database.h>
+#include <apt-pkg/dirstream.h>
+#include <apt-pkg/tagfile.h>
+
+class debDebFile
+{
+   protected:
+   
+   FileFd &File;
+   ARArchive AR;
+   
+   bool CheckMember(const char *Name);
+   
+   public:
+
+   class ControlExtract;
+   class MemControlExtract;
+   
+   bool ExtractControl(pkgDataBase &DB);
+   bool ExtractArchive(pkgDirStream &Stream);
+   pkgCache::VerIterator MergeControl(pkgDataBase &DB);
+   const ARArchive::Member *GotoMember(const char *Name);
+   inline FileFd &GetFile() {return File;};
+   
+   debDebFile(FileFd &File);
+};
+
+class debDebFile::ControlExtract : public pkgDirStream
+{
+   public:
+   
+   virtual bool DoItem(Item &Itm,int &Fd);
+};
+
+class debDebFile::MemControlExtract : public pkgDirStream
+{
+   bool IsControl;
+   
+   public:
+   
+   char *Control;
+   pkgTagSection Section;
+   unsigned long Length;
+   string Member;
+   
+   // Members from DirStream
+   virtual bool DoItem(Item &Itm,int &Fd);
+   virtual bool Process(Item &Itm,const unsigned char *Data,
+			unsigned long Size,unsigned long Pos);
+   
+
+   // Helpers
+   bool Read(debDebFile &Deb);
+   bool TakeControl(const void *Data,unsigned long Size);
+      
+   MemControlExtract() : IsControl(false), Control(0), Length(0), Member("control") {};
+   MemControlExtract(string Member) : IsControl(false), Control(0), Length(0), Member(Member) {};
+   ~MemControlExtract() {delete [] Control;};   
+};
+									/*}}}*/
+
+#endif

+ 490 - 0
apt-inst/deb/dpkgdb.cc

@@ -0,0 +1,490 @@
+// -*- mode: cpp; mode: fold -*-
+// Description								/*{{{*/
+// $Id: dpkgdb.cc,v 1.2 2001/02/20 07:03:17 jgg Exp $
+/* ######################################################################
+
+   DPKGv1 Database Implemenation
+   
+   This class provides parsers and other implementations for the DPKGv1
+   database. It reads the diversion file, the list files and the status
+   file to build both the list of currently installed files and the 
+   currently installed package list.
+   
+   ##################################################################### */
+									/*}}}*/
+// Include Files							/*{{{*/
+#ifdef __GNUG__
+#pragma implementation "apt-pkg/dpkgdb.h"
+#endif
+
+#include <apt-pkg/dpkgdb.h>
+#include <apt-pkg/configuration.h>
+#include <apt-pkg/error.h>
+#include <apt-pkg/progress.h>
+#include <apt-pkg/tagfile.h>
+#include <apt-pkg/strutl.h>
+
+#include <stdio.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+									/*}}}*/
+
+// EraseDir - Erase A Directory						/*{{{*/
+// ---------------------------------------------------------------------
+/* This is necessary to create a new empty sub directory. The caller should
+   invoke mkdir after this with the proper permissions and check for 
+   error. Maybe stick this in fileutils */
+static bool EraseDir(const char *Dir)
+{
+   // First we try a simple RM
+   if (rmdir(Dir) == 0 ||
+       errno == ENOENT)
+      return true;
+   
+   // A file? Easy enough..
+   if (errno == ENOTDIR)
+   {
+      if (unlink(Dir) != 0)
+	 return _error->Errno("unlink","Failed to remove %s",Dir);
+      return true;
+   }
+   
+   // Should not happen
+   if (errno != ENOTEMPTY)
+      return _error->Errno("rmdir","Failed to remove %s",Dir);
+   
+   // Purge it using rm
+   int Pid = ExecFork();
+
+   // Spawn the subprocess
+   if (Pid == 0)
+   {
+      execlp(_config->Find("Dir::Bin::rm","/bin/rm").c_str(),
+	     "rm","-rf","--",Dir,0);
+      _exit(100);
+   }
+   return ExecWait(Pid,_config->Find("dir::bin::rm","/bin/rm").c_str());
+}
+									/*}}}*/
+// DpkgDB::debDpkgDB - Constructor					/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+debDpkgDB::debDpkgDB() : CacheMap(0), FileMap(0)
+{
+   AdminDir = flNotFile(_config->Find("Dir::State::status"));   
+   DiverInode = 0;
+   DiverTime = 0;
+}
+									/*}}}*/
+// DpkgDB::~debDpkgDB - Destructor					/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+debDpkgDB::~debDpkgDB()
+{
+   delete Cache;
+   Cache = 0;
+   delete CacheMap;
+   CacheMap = 0;
+   
+   delete FList;
+   FList = 0;
+   delete FileMap;
+   FileMap = 0;
+}
+									/*}}}*/
+// DpkgDB::InitMetaTmp - Get the temp dir for meta information		/*{{{*/
+// ---------------------------------------------------------------------
+/* This creats+empties the meta temporary directory /var/lib/dpkg/tmp.ci
+   Only one package at a time can be using the returned meta directory. */
+bool debDpkgDB::InitMetaTmp(string &Dir)
+{
+   string Tmp = AdminDir + "tmp.ci/";
+   if (EraseDir(Tmp.c_str()) == false)
+      return _error->Error("Unable to create %s",Tmp.c_str());
+   if (mkdir(Tmp.c_str(),0755) != 0)
+      return _error->Errno("mkdir","Unable to create %s",Tmp.c_str());
+   
+   // Verify it is on the same filesystem as the main info directory
+   dev_t Dev;
+   struct stat St;
+   if (stat((AdminDir + "info").c_str(),&St) != 0)
+      return _error->Errno("stat","Failed to stat %sinfo",AdminDir.c_str());
+   Dev = St.st_dev;
+   if (stat(Tmp.c_str(),&St) != 0)
+      return _error->Errno("stat","Failed to stat %s",Tmp.c_str());
+   if (Dev != St.st_dev)
+      return _error->Error("The info and temp directories need to be on the same filesystem");
+   
+   // Done
+   Dir = Tmp;
+   return true;
+}
+									/*}}}*/
+// DpkgDB::ReadyPkgCache - Prepare the cache with the current status	/*{{{*/
+// ---------------------------------------------------------------------
+/* This reads in the status file into an empty cache. This really needs 
+   to be somehow unified with the high level APT notion of the Database
+   directory, but there is no clear way on how to do that yet. */
+bool debDpkgDB::ReadyPkgCache(OpProgress &Progress)
+{
+   if (Cache != 0)
+   {  
+      Progress.OverallProgress(1,1,1,"Reading Package Lists");      
+      return true;
+   }
+   
+   if (CacheMap != 0)
+   {
+      delete CacheMap;
+      CacheMap = 0;
+   }
+   
+   if (pkgMakeOnlyStatusCache(Progress,&CacheMap) == false)
+      return false;
+   Cache->DropProgress();
+   
+   return true;
+}
+									/*}}}*/
+// DpkgDB::ReadFList - Read the File Listings in 			/*{{{*/
+// ---------------------------------------------------------------------
+/* This reads the file listing in from the state directory. This is a 
+   performance critical routine, as it needs to parse about 50k lines of
+   text spread over a hundred or more files. For an initial cold start
+   most of the time is spent in reading file inodes and so on, not 
+   actually parsing. */
+bool debDpkgDB::ReadFList(OpProgress &Progress)
+{
+   // Count the number of packages we need to read information for
+   unsigned long Total = 0;
+   pkgCache &Cache = this->Cache->GetCache();
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   {
+      // Only not installed packages have no files.
+      if (I->CurrentState == pkgCache::State::NotInstalled)
+	 continue;
+      Total++;
+   }
+
+   /* Switch into the admin dir, this prevents useless lookups for the 
+      path components */
+   string Cwd = SafeGetCWD();
+   if (chdir((AdminDir + "info/").c_str()) != 0)
+      return _error->Errno("chdir","Failed to change to the admin dir %sinfo",AdminDir.c_str());
+   
+   // Allocate a buffer. Anything larger than this buffer will be mmaped
+   unsigned long BufSize = 32*1024;
+   char *Buffer = new char[BufSize];
+
+   // Begin Loading them
+   unsigned long Count = 0;
+   char Name[300];
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   {
+      /* Only not installed packages have no files. ConfFile packages have
+         file lists but we don't want to read them in */
+      if (I->CurrentState == pkgCache::State::NotInstalled ||
+	  I->CurrentState == pkgCache::State::ConfigFiles)
+	 continue;
+
+      // Fetch a package handle to associate with the file
+      pkgFLCache::PkgIterator FlPkg = FList->GetPkg(I.Name(),0,true);
+      if (FlPkg.end() == true)
+      {
+	 _error->Error("Internal Error getting a Package Name");
+	 break;
+      }
+      
+      Progress.OverallProgress(Count,Total,1,"Reading File Listing");
+     
+      // Open the list file
+      snprintf(Name,sizeof(Name),"%s.list",I.Name());
+      int Fd = open(Name,O_RDONLY);
+      
+      /* Okay this is very strange and bad.. Best thing is to bail and
+         instruct the user to look into it. */
+      struct stat Stat;
+      if (Fd == -1 || fstat(Fd,&Stat) != 0)
+      {
+	 _error->Errno("open","Failed to open the list file '%sinfo/%s'. If you "
+		       "cannot restore this file then make it empty "
+		       "and immediately re-install the same version of the package!",
+		       AdminDir.c_str(),Name);
+	 break;
+      }
+      
+      // Set File to be a memory buffer containing the whole file
+      char *File;
+      if ((unsigned)Stat.st_size < BufSize)
+      {
+	 if (read(Fd,Buffer,Stat.st_size) != Stat.st_size)
+	 {
+	    _error->Errno("read","Failed reading the list file %sinfo/%s",
+			  AdminDir.c_str(),Name);
+	    close(Fd);
+	    break;
+	 }
+	 File = Buffer;
+      }
+      else
+      {
+	 // Use mmap
+	 File = (char *)mmap(0,Stat.st_size,PROT_READ,MAP_PRIVATE,Fd,0);
+	 if (File == (char *)(-1))
+	 {
+	    _error->Errno("mmap","Failed reading the list file %sinfo/%s",
+			  AdminDir.c_str(),Name);
+	    close(Fd);
+	    break;
+	 }	    
+      }
+      
+      // Parse it
+      const char *Start = File;
+      const char *End = File;
+      const char *Finish = File + Stat.st_size;
+      for (; End < Finish; End++)
+      {
+	 // Not an end of line
+	 if (*End != '\n' && End + 1 < Finish)
+	    continue;
+
+	 // Skip blank lines
+	 if (End - Start > 1)
+	 {
+	    pkgFLCache::NodeIterator Node = FList->GetNode(Start,End,
+ 					      FlPkg.Offset(),true,false);
+	    if (Node.end() == true)
+	    {
+	       _error->Error("Internal Error getting a Node");
+	       break;
+	    }
+	 }
+	 
+	 // Skip past the end of line
+	 for (; *End == '\n' && End < Finish; End++);
+	 Start = End;
+      }      
+      
+      close(Fd);
+      if ((unsigned)Stat.st_size >= BufSize)
+	 munmap((caddr_t)File,Stat.st_size);
+      
+      // Failed
+      if (End < Finish)
+	 break;
+      
+      Count++;
+   }
+
+   delete [] Buffer;
+   if (chdir(Cwd.c_str()) != 0)
+      chdir("/");
+   
+   return !_error->PendingError();
+}
+									/*}}}*/
+// DpkgDB::ReadDiversions - Load the diversions file			/*{{{*/
+// ---------------------------------------------------------------------
+/* Read the diversion file in from disk. This is usually invoked by 
+   LoadChanges before performing an operation that uses the FLCache. */
+bool debDpkgDB::ReadDiversions()
+{
+   struct stat Stat;
+   if (stat((AdminDir + "diversions").c_str(),&Stat) != 0)
+      return true;
+   
+   if (_error->PendingError() == true)
+      return false;
+   
+   FILE *Fd = fopen((AdminDir + "diversions").c_str(),"r");
+   if (Fd == 0)
+      return _error->Errno("fopen","Failed to open the diversions file %sdiversions",AdminDir.c_str());
+	
+   FList->BeginDiverLoad();
+   while (1)
+   {
+      char From[300];
+      char To[300];
+      char Package[100];
+   
+      // Read the three lines in
+      if (fgets(From,sizeof(From),Fd) == 0)
+	 break;
+      if (fgets(To,sizeof(To),Fd) == 0 ||
+	  fgets(Package,sizeof(Package),Fd) == 0)
+      {
+	 _error->Error("The diversion file is corrupted");
+	 break;
+      }
+      
+      // Strip the \ns
+      unsigned long Len = strlen(From);
+      if (Len < 2 || From[Len-1] != '\n')
+	 _error->Error("Invalid line in the diversion file: %s",From);
+      else
+	 From[Len-1] = 0;
+      Len = strlen(To);
+      if (Len < 2 || To[Len-1] != '\n')
+	 _error->Error("Invalid line in the diversion file: %s",To);
+      else
+	 To[Len-1] = 0;     
+      Len = strlen(Package);
+      if (Len < 2 || Package[Len-1] != '\n')
+	 _error->Error("Invalid line in the diversion file: %s",Package);
+      else
+	 Package[Len-1] = 0;
+      
+      // Make sure the lines were parsed OK
+      if (_error->PendingError() == true)
+	 break;
+      
+      // Fetch a package
+      if (strcmp(Package,":") == 0)
+	 Package[0] = 0;
+      pkgFLCache::PkgIterator FlPkg = FList->GetPkg(Package,0,true);
+      if (FlPkg.end() == true)
+      {
+	 _error->Error("Internal Error getting a Package Name");
+	 break;
+      }
+      
+      // Install the diversion
+      if (FList->AddDiversion(FlPkg,From,To) == false)
+      {
+	 _error->Error("Internal Error adding a diversion");
+	 break;
+      }
+   }
+   if (_error->PendingError() == false)
+      FList->FinishDiverLoad();
+   
+   DiverInode = Stat.st_ino;
+   DiverTime = Stat.st_mtime;
+   
+   fclose(Fd);
+   return !_error->PendingError();
+}
+									/*}}}*/
+// DpkgDB::ReadFileList - Read the file listing				/*{{{*/
+// ---------------------------------------------------------------------
+/* Read in the file listing. The file listing is created from three
+   sources, *.list, Conffile sections and the Diversion table. */
+bool debDpkgDB::ReadyFileList(OpProgress &Progress)
+{
+   if (Cache == 0)
+      return _error->Error("The pkg cache must be initialize first");
+   if (FList != 0)
+   {
+      Progress.OverallProgress(1,1,1,"Reading File List");
+      return true;
+   }
+   
+   // Create the cache and read in the file listing
+   FileMap = new DynamicMMap(MMap::Public);
+   FList = new pkgFLCache(*FileMap);
+   if (_error->PendingError() == true || 
+       ReadFList(Progress) == false ||
+       ReadConfFiles() == false || 
+       ReadDiversions() == false)
+   {
+      delete FList;
+      delete FileMap;
+      FileMap = 0;
+      FList = 0;
+      return false;
+   }
+      
+   cout << "Node: " << FList->HeaderP->NodeCount << ',' << FList->HeaderP->UniqNodes << endl;
+   cout << "Dir: " << FList->HeaderP->DirCount << endl;
+   cout << "Package: " << FList->HeaderP->PackageCount << endl;
+   cout << "HashSize: " << FList->HeaderP->HashSize << endl;
+   cout << "Size: " << FileMap->Size() << endl;
+   cout << endl;
+
+   return true;
+}
+									/*}}}*/
+// DpkgDB::ReadConfFiles - Read the conf file sections from the s-file	/*{{{*/
+// ---------------------------------------------------------------------
+/* Reading the conf files is done by reparsing the status file. This is
+   actually rather fast so it is no big deal. */
+bool debDpkgDB::ReadConfFiles()
+{
+   FileFd File(_config->FindFile("Dir::State::status"),FileFd::ReadOnly);
+   pkgTagFile Tags(&File);
+   if (_error->PendingError() == true)
+      return false;
+   
+   pkgTagSection Section;   
+   while (1)
+   {
+      // Skip to the next section
+      unsigned long Offset = Tags.Offset();
+      if (Tags.Step(Section) == false)
+	 break;
+	 
+      // Parse the line
+      const char *Start;
+      const char *Stop;
+      if (Section.Find("Conffiles",Start,Stop) == false)
+	 continue;
+
+      const char *PkgStart;
+      const char *PkgEnd;
+      if (Section.Find("Package",PkgStart,PkgEnd) == false)
+	 return _error->Error("Failed to find a Package: Header, offset %lu",Offset);
+
+      // Snag a package record for it
+      pkgFLCache::PkgIterator FlPkg = FList->GetPkg(PkgStart,PkgEnd,true);
+      if (FlPkg.end() == true)
+	 return _error->Error("Internal Error getting a Package Name");
+
+      // Parse the conf file lines
+      while (1)
+      {
+	 for (; isspace(*Start) != 0 && Start < Stop; Start++);
+	 if (Start == Stop)
+	    break;
+
+	 // Split it into words
+	 const char *End = Start;
+	 for (; isspace(*End) == 0 && End < Stop; End++);
+	 const char *StartMd5 = End;
+	 for (; isspace(*StartMd5) != 0 && StartMd5 < Stop; StartMd5++);
+	 const char *EndMd5 = StartMd5;
+	 for (; isspace(*EndMd5) == 0 && EndMd5 < Stop; EndMd5++);
+	 if (StartMd5 == EndMd5 || Start == End)
+	    return _error->Error("Bad ConfFile section in the status file. Offset %lu",Offset);
+	 	 
+	 // Insert a new entry
+	 unsigned char MD5[16];
+	 if (Hex2Num(StartMd5,EndMd5,MD5,16) == false)
+	    return _error->Error("Error parsing MD5. Offset %lu",Offset);
+	 
+	 if (FList->AddConfFile(Start,End,FlPkg,MD5) == false)
+	    return false;
+	 Start = EndMd5;
+      }      
+   }   
+   
+   return true;
+}
+									/*}}}*/
+// DpkgDB::LoadChanges - Read in any changed state files		/*{{{*/
+// ---------------------------------------------------------------------
+/* The only file in the dpkg system that can change while packages are
+   unpacking is the diversions file. */
+bool debDpkgDB::LoadChanges()
+{
+   struct stat Stat;
+   if (stat((AdminDir + "diversions").c_str(),&Stat) != 0)
+      return true;
+   if (DiverInode == Stat.st_ino && DiverTime == Stat.st_mtime)
+      return true;
+   return ReadDiversions();
+}
+									/*}}}*/

+ 53 - 0
apt-inst/deb/dpkgdb.h

@@ -0,0 +1,53 @@
+// -*- mode: cpp; mode: fold -*-
+// Description								/*{{{*/
+// $Id: dpkgdb.h,v 1.2 2001/02/20 07:03:17 jgg Exp $
+/* ######################################################################
+
+   DPKGv1 Data Base Implemenation
+   
+   The DPKGv1 database is typically stored in /var/lib/dpkg/. For 
+   DPKGv1 the 'meta' information is the contents of the .deb control.tar.gz
+   member prepended by the package name. The meta information is unpacked
+   in its temporary directory and then migrated into the main list dir
+   at a checkpoint.
+   
+   Journaling is providing by syncronized file writes to the updates sub
+   directory.
+
+   ##################################################################### */
+									/*}}}*/
+#ifndef PKGLIB_DPKGDB_H
+#define PKGLIB_DPKGDB_H
+
+#ifdef __GNUG__
+#pragma interface "apt-pkg/dpkgdb.h"
+#endif
+
+#include <apt-pkg/database.h>
+
+class debDpkgDB : public pkgDataBase
+{
+   protected:
+   
+   string AdminDir;
+   DynamicMMap *CacheMap;
+   DynamicMMap *FileMap;
+   unsigned long DiverInode;
+   signed long DiverTime;
+   
+   virtual bool InitMetaTmp(string &Dir);
+   bool ReadFList(OpProgress &Progress);
+   bool ReadDiversions();
+   bool ReadConfFiles();
+      
+   public:
+
+   virtual bool ReadyFileList(OpProgress &Progress);
+   virtual bool ReadyPkgCache(OpProgress &Progress);
+   virtual bool LoadChanges();
+   
+   debDpkgDB();
+   virtual ~debDpkgDB();
+};
+
+#endif

+ 103 - 0
apt-inst/dirstream.cc

@@ -0,0 +1,103 @@
+// -*- mode: cpp; mode: fold -*-
+// Description								/*{{{*/
+// $Id: dirstream.cc,v 1.2 2001/02/20 07:03:16 jgg Exp $
+/* ######################################################################
+
+   Directory Stream 
+   
+   This class provides a simple basic extractor that can be used for
+   a number of purposes.
+   
+   ##################################################################### */
+									/*}}}*/
+// Include Files							/*{{{*/
+#ifdef __GNUG__
+#pragma implementation "apt-pkg/dirstream.h"
+#endif
+
+#include <apt-pkg/dirstream.h>
+#include <apt-pkg/error.h>
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <utime.h>
+#include <unistd.h>
+									/*}}}*/
+
+// DirStream::DoItem - Process an item					/*{{{*/
+// ---------------------------------------------------------------------
+/* This is a very simple extractor, it does not deal with things like
+   overwriting directories with files and so on. */
+bool pkgDirStream::DoItem(Item &Itm,int &Fd)
+{
+   switch (Itm.Type)
+   {
+      case Item::File:
+      {
+	 /* Open the output file, NDELAY is used to prevent this from 
+	    blowing up on device special files.. */
+	 int iFd = open(Itm.Name,O_NDELAY|O_WRONLY|O_CREAT|O_TRUNC|O_APPEND,
+		       Itm.Mode);
+	 if (iFd < 0)
+	    return _error->Errno("open","Failed write file %s",
+				 Itm.Name);
+	 
+	 // fchmod deals with umask and fchown sets the ownership
+	 if (fchmod(iFd,Itm.Mode) != 0)
+	    return _error->Errno("fchmod","Failed write file %s",
+				 Itm.Name);
+	 if (fchown(iFd,Itm.UID,Itm.GID) != 0 && errno != EPERM)
+	    return _error->Errno("fchown","Failed write file %s",
+				 Itm.Name);
+	 Fd = iFd;
+	 return true;
+      }
+      
+      case Item::HardLink:
+      case Item::SymbolicLink:
+      case Item::CharDevice:
+      case Item::BlockDevice:
+      case Item::Directory:
+      case Item::FIFO:
+      break;
+   }
+   
+   return true;
+}
+									/*}}}*/
+// DirStream::FinishedFile - Finished processing a file			/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool pkgDirStream::FinishedFile(Item &Itm,int Fd)
+{
+   if (Fd < 0)
+      return true;
+   
+   if (close(Fd) != 0)
+      return _error->Errno("close","Failed to close file %s",Itm.Name);
+
+   /* Set the modification times. The only way it can fail is if someone
+      has futzed with our file, which is intolerable :> */
+   struct utimbuf Time;
+   Time.actime = Itm.MTime;
+   Time.modtime = Itm.MTime;
+   if (utime(Itm.Name,&Time) != 0)
+      _error->Errno("utime","Failed to close file %s",Itm.Name);
+   
+   return true;   
+}
+									/*}}}*/
+// DirStream::Fail - Failed processing a file				/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool pkgDirStream::Fail(Item &Itm,int Fd)
+{
+   if (Fd < 0)
+      return true;
+   
+   close(Fd);
+   return false;
+}
+									/*}}}*/

+ 61 - 0
apt-inst/dirstream.h

@@ -0,0 +1,61 @@
+// -*- mode: cpp; mode: fold -*-
+// Description								/*{{{*/
+// $Id: dirstream.h,v 1.2 2001/02/20 07:03:16 jgg Exp $
+/* ######################################################################
+
+   Directory Stream 
+
+   When unpacking the contents of the archive are passed into a directory
+   stream class for analysis and processing. The class controls all aspects
+   of actually writing the directory stream from disk. The low level
+   archive handlers are only responsible for decoding the archive format
+   and sending events (via method calls) to the specified directory
+   stream.
+   
+   When unpacking a real file the archive handler is passed back a file 
+   handle to write the data to, this is to support strange 
+   archives+unpacking methods. If that fd is -1 then the file data is 
+   simply ignored.
+   
+   The provided defaults do the 'Right Thing' for a normal unpacking
+   process (ie 'tar')
+   
+   ##################################################################### */
+									/*}}}*/
+#ifndef PKGLIB_DIRSTREAM_H
+#define PKGLIB_DIRSTREAM_H
+
+#ifdef __GNUG__
+#pragma interface "apt-pkg/dirstream.h"
+#endif
+
+class pkgDirStream
+{ 
+   public:
+
+   // All possible information about a component
+   struct Item
+   {
+      enum Type_t {File, HardLink, SymbolicLink, CharDevice, BlockDevice,
+	           Directory, FIFO} Type;
+      char *Name;
+      char *LinkTarget;
+      unsigned long Mode;
+      unsigned long UID;
+      unsigned long GID;
+      unsigned long Size;
+      unsigned long MTime;
+      unsigned long Major;
+      unsigned long Minor;
+   };
+   
+   virtual bool DoItem(Item &Itm,int &Fd);
+   virtual bool Fail(Item &Itm,int Fd);
+   virtual bool FinishedFile(Item &Itm,int Fd);
+   virtual bool Process(Item &Itm,const unsigned char *Data,
+			unsigned long Size,unsigned long Pos) {return true;};
+      
+   virtual ~pkgDirStream() {};   
+};
+
+#endif

+ 5 - 0
apt-inst/dpkg-diffs.txt

@@ -0,0 +1,5 @@
+- Replacing directories with files
+  dpkg permits this with the weak condition that the directory is owned only
+  by the package. APT requires that the directory have no files that are not
+  owned by the package. Replaces are specifically not checked to prevent
+  file list corruption.

+ 509 - 0
apt-inst/extract.cc

@@ -0,0 +1,509 @@
+// -*- mode: cpp; mode: fold -*-
+// Description								/*{{{*/
+// $Id: extract.cc,v 1.2 2001/02/20 07:03:16 jgg Exp $
+/* ######################################################################
+
+   Archive Extraction Directory Stream
+   
+   Extraction for each file is a bit of an involved process. Each object
+   undergoes an atomic backup, overwrite, erase sequence. First the
+   object is unpacked to '.dpkg.new' then the original is hardlinked to
+   '.dpkg.tmp' and finally the new object is renamed to overwrite the old
+   one. From an external perspective the file never ceased to exist.
+   After the archive has been sucessfully unpacked the .dpkg.tmp files 
+   are erased. A failure causes all the .dpkg.tmp files to be restored.
+   
+   Decisions about unpacking go like this:
+      - Store the original filename in the file listing
+      - Resolve any diversions that would effect this file, all checks
+        below apply to the diverted name, not the real one.
+      - Resolve any symlinked configuration files.
+      - If the existing file does not exist then .dpkg-tmp is checked for.
+        [Note, this is reduced to only check if a file was expected to be
+         there]
+      - If the existing link/file is not a directory then it is replaced
+        irregardless
+      - If the existing link/directory is being replaced by a directory then
+        absolutely nothing happens.
+      - If the existing link/directory is being replaced by a link then
+        absolutely nothing happens.
+      - If the existing link/directory is being replaced by a non-directory
+        then this will abort if the package is not the sole owner of the
+        directory. [Note, this is changed to not happen if the directory
+        non-empty - that is, it only includes files that are part of this
+        package - prevents removing user files accidentally.]
+      - If the non-directory exists in the listing database and it
+        does not belong to the current package then an overwrite condition
+        is invoked. 
+   
+   As we unpack we record the file list differences in the FL cache. If
+   we need to unroll the the FL cache knows which files have been unpacked
+   and can undo. When we need to erase then it knows which files have not 
+   been unpacked.
+   
+   ##################################################################### */
+									/*}}}*/
+// Include Files							/*{{{*/
+#ifdef __GNUG__
+#pragma implementation "apt-pkg/extract.h"
+#endif
+#include <apt-pkg/extract.h>
+#include <apt-pkg/error.h>
+#include <apt-pkg/debversion.h>
+
+#include <sys/stat.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <dirent.h>
+									/*}}}*/
+
+static const char *TempExt = "dpkg-tmp";
+//static const char *NewExt = "dpkg-new";
+
+// Extract::pkgExtract - Constructor					/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+pkgExtract::pkgExtract(pkgFLCache &FLCache,pkgCache::VerIterator Ver) : 
+                       FLCache(FLCache), Ver(Ver)
+{
+   FLPkg = FLCache.GetPkg(Ver.ParentPkg().Name(),true);
+   if (FLPkg.end() == true)
+      return;
+   Debug = true;
+}
+									/*}}}*/
+// Extract::DoItem - Handle a single item from the stream		/*{{{*/
+// ---------------------------------------------------------------------
+/* This performs the setup for the extraction.. */
+bool pkgExtract::DoItem(Item &Itm,int &Fd)
+{
+   char Temp[sizeof(FileName)];
+   
+   /* Strip any leading/trailing /s from the filename, then copy it to the
+      temp buffer and re-apply the leading / We use a class variable
+      to store the new filename for use by the three extraction funcs */
+   char *End = FileName+1;
+   const char *I = Itm.Name;
+   for (; *I != 0 && *I == '/'; I++);
+   *FileName = '/';
+   for (; *I != 0 && End < FileName + sizeof(FileName); I++, End++)
+      *End = *I;
+   if (End + 20 >= FileName + sizeof(FileName))
+      return _error->Error("The path %s is too long",Itm.Name);   
+   for (; End > FileName && End[-1] == '/'; End--);
+   *End = 0;
+   Itm.Name = FileName;
+   
+   /* Lookup the file. Nde is the file [group] we are going to write to and
+      RealNde is the actual node we are manipulating. Due to diversions
+      they may be entirely different. */
+   pkgFLCache::NodeIterator Nde = FLCache.GetNode(Itm.Name,End,0,false,false);
+   pkgFLCache::NodeIterator RealNde = Nde;
+      
+   // See if the file is already in the file listing
+   unsigned long FileGroup = RealNde->File;
+   for (; RealNde.end() == false && FileGroup == RealNde->File; RealNde++)
+      if (RealNde.RealPackage() == FLPkg)
+	 break;
+
+   // Nope, create an entry
+   if (RealNde.end() == true)
+   {
+      RealNde = FLCache.GetNode(Itm.Name,End,FLPkg.Offset(),true,false);
+      if (RealNde.end() == true)
+	 return false;
+      RealNde->Flags |= pkgFLCache::Node::NewFile;
+   }
+
+   /* Check if this entry already was unpacked. The only time this should 
+      ever happen is if someone has hacked tar to support capabilities, in
+      which case this needs to be modified anyhow.. */
+   if ((RealNde->Flags & pkgFLCache::Node::Unpacked) ==
+       pkgFLCache::Node::Unpacked)
+      return _error->Error("Unpacking %s more than once",Itm.Name);
+   
+   if (Nde.end() == true)
+      Nde = RealNde;
+
+   /* Consider a diverted file - We are not permitted to divert directories,
+      but everything else is fair game (including conf files!) */
+   if ((Nde->Flags & pkgFLCache::Node::Diversion) != 0)
+   {
+      if (Itm.Type == Item::Directory)
+	 return _error->Error("The directory %s is diverted",Itm.Name);
+
+      /* A package overwriting a diversion target is just the same as 
+         overwriting a normally owned file and is checked for below in
+	 the overwrites mechanism */
+
+      /* If this package is trying to overwrite the target of a diversion, 
+         that is never, ever permitted */
+      pkgFLCache::DiverIterator Div = Nde.Diversion();
+      if (Div.DivertTo() == Nde)
+	 return _error->Error("The package is trying to write to the "
+			      "diversion target %s/%s",Nde.DirN(),Nde.File());
+      
+      // See if it is us and we are following it in the right direction
+      if (Div->OwnerPkg != FLPkg.Offset() && Div.DivertFrom() == Nde)
+      {
+	 Nde = Div.DivertTo();
+	 End = FileName + snprintf(FileName,sizeof(FileName)-20,"%s/%s",
+				   Nde.DirN(),Nde.File());
+	 if (End <= FileName)
+	    return _error->Error("The diversion path is too long");
+      }      
+   }
+   
+   // Deal with symlinks and conf files
+   if ((RealNde->Flags & pkgFLCache::Node::NewConfFile) == 
+       pkgFLCache::Node::NewConfFile)
+   {
+      string Res = flNoLink(Itm.Name);
+      if (Res.length() > sizeof(FileName))
+	 return _error->Error("The path %s is too long",Res.c_str());
+      if (Debug == true)
+	 clog << "Followed conf file from " << FileName << " to " << Res << endl;
+      Itm.Name = strcpy(FileName,Res.c_str());      
+   }
+   
+   /* Get information about the existing file, and attempt to restore
+      a backup if it does not exist */
+   struct stat LExisting;
+   bool EValid = false;
+   if (lstat(Itm.Name,&LExisting) != 0)
+   {
+      // This is bad news.
+      if (errno != ENOENT)
+	 return _error->Errno("stat","Failed to stat %s",Itm.Name);
+      
+      // See if we can recover the backup file
+      if (Nde.end() == false)
+      {
+	 snprintf(Temp,sizeof(Temp),"%s.%s",Itm.Name,TempExt);
+	 if (rename(Temp,Itm.Name) != 0 && errno != ENOENT)
+	    return _error->Errno("rename","Failed to rename %s to %s",
+				 Temp,Itm.Name);
+	 if (stat(Itm.Name,&LExisting) != 0)
+	 {
+	    if (errno != ENOENT)
+	       return _error->Errno("stat","Failed to stat %s",Itm.Name);
+	 }	 
+	 else
+	    EValid = true;
+      }
+   }
+   else
+      EValid = true;
+   
+   /* If the file is a link we need to stat its destination, get the
+      existing file modes */
+   struct stat Existing = LExisting;
+   if (EValid == true && S_ISLNK(Existing.st_mode))
+   {
+      if (stat(Itm.Name,&Existing) != 0)
+      {
+	 if (errno != ENOENT)
+	    return _error->Errno("stat","Failed to stat %s",Itm.Name);
+	 Existing = LExisting;
+      }      
+   }
+   
+   // We pretend a non-existing file looks like it is a normal file
+   if (EValid == false)
+      Existing.st_mode = S_IFREG;
+   
+   /* Okay, at this point 'Existing' is the stat information for the
+      real non-link file */
+   
+   /* The only way this can be a no-op is if a directory is being
+      replaced by a directory or by a link */
+   if (S_ISDIR(Existing.st_mode) != 0 && 
+       (Itm.Type == Item::Directory || Itm.Type == Item::SymbolicLink))
+      return true;
+      
+   /* Non-Directory being replaced by non-directory. We check for over
+      writes here. */
+   if (Nde.end() == false)
+   {
+      if (HandleOverwrites(Nde) == false)
+	 return false;
+   }
+   
+   /* Directory being replaced by a non-directory - this needs to see if
+      the package is the owner and then see if the directory would be
+      empty after the package is removed [ie no user files will be 
+      erased] */
+   if (S_ISDIR(Existing.st_mode) != 0)
+   {
+      if (CheckDirReplace(Itm.Name) == false)
+	 return _error->Error("The directory %s is being replaced by a non-directory",Itm.Name);
+   }
+   
+   if (Debug == true)
+      clog << "Extract " << string(Itm.Name,End) << endl;
+/*   if (Count != 0)
+      return _error->Error("Done");*/
+   
+   return true;
+}
+									/*}}}*/
+// Extract::Finished - Sequence finished, erase the temp files		/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool pkgExtract::Finished()
+{
+   return true;
+}
+									/*}}}*/
+// Extract::Aborted - Sequence aborted, undo all our unpacking		/*{{{*/
+// ---------------------------------------------------------------------
+/* This undoes everything that was done by all calls to the DoItem method
+   and restores the File Listing cache to its original form. It bases its
+   actions on the flags value for each node in the cache. */
+bool pkgExtract::Aborted()
+{
+   if (Debug == true)
+      clog << "Aborted, backing out" << endl;
+   
+   pkgFLCache::NodeIterator Files = FLPkg.Files();
+   map_ptrloc *Last = &FLPkg->Files;
+   
+   /* Loop over all files, restore those that have been unpacked from their
+      dpkg-tmp entires */
+   while (Files.end() == false)
+   {
+      // Locate the hash bucket for the node and locate its group head
+      pkgFLCache::NodeIterator Nde(FLCache,FLCache.HashNode(Files));
+      for (; Nde.end() == false && Files->File != Nde->File; Nde++);
+      if (Nde.end() == true)
+	 return _error->Error("Failed to locate node in its hash bucket");
+      
+      if (snprintf(FileName,sizeof(FileName)-20,"%s/%s",
+		   Nde.DirN(),Nde.File()) <= 0)
+	 return _error->Error("The path is too long");
+      
+      // Deal with diversions
+      if ((Nde->Flags & pkgFLCache::Node::Diversion) != 0)
+      {
+	 pkgFLCache::DiverIterator Div = Nde.Diversion();
+	 
+	 // See if it is us and we are following it in the right direction
+	 if (Div->OwnerPkg != FLPkg.Offset() && Div.DivertFrom() == Nde)
+	 {
+	    Nde = Div.DivertTo();
+	    if (snprintf(FileName,sizeof(FileName)-20,"%s/%s",
+			 Nde.DirN(),Nde.File()) <= 0)
+	       return _error->Error("The diversion path is too long");
+	 }
+      }      
+      
+      // Deal with overwrites+replaces
+      for (; Nde.end() == false && Files->File == Nde->File; Nde++)
+      {
+	 if ((Nde->Flags & pkgFLCache::Node::Replaced) == 
+	     pkgFLCache::Node::Replaced)
+	 {
+	    if (Debug == true)
+	       clog << "De-replaced " << FileName << " from " << Nde.RealPackage()->Name << endl;
+	    Nde->Flags &= ~pkgFLCache::Node::Replaced;
+	 }	 
+      }      
+      
+      // Undo the change in the filesystem
+      if (Debug == true)
+	 clog << "Backing out " << FileName;
+      
+      // Remove a new node
+      if ((Files->Flags & pkgFLCache::Node::NewFile) ==
+	 pkgFLCache::Node::NewFile)
+      {
+	 if (Debug == true)
+	    clog << " [new node]" << endl;
+	 pkgFLCache::Node *Tmp = Files;
+	 Files++;
+	 *Last = Tmp->NextPkg;
+	 Tmp->NextPkg = 0;
+
+	 FLCache.DropNode(Tmp - FLCache.NodeP);
+      }
+      else
+      {
+	 if (Debug == true)
+	    clog << endl;
+	 
+	 Last = &Files->NextPkg;
+	 Files++;
+      }      	 
+   }
+   
+   return true;
+}
+									/*}}}*/
+// Extract::Fail - Extraction of a file Failed				/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool pkgExtract::Fail(Item &Itm,int Fd)
+{
+   return pkgDirStream::Fail(Itm,Fd);
+}
+									/*}}}*/
+// Extract::FinishedFile - Finished a file				/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool pkgExtract::FinishedFile(Item &Itm,int Fd)
+{
+   return pkgDirStream::FinishedFile(Itm,Fd);
+}
+									/*}}}*/
+// Extract::HandleOverwrites - See if a replaces covers this overwrite	/*{{{*/
+// ---------------------------------------------------------------------
+/* Check if the file is in a package that is being replaced by this 
+   package or if the file is being overwritten. Note that if the file
+   is really a directory but it has been erased from the filesystem 
+   this will fail with an overwrite message. This is a limitation of the
+   dpkg file information format. 
+ 
+   XX If a new package installs and another package replaces files in this
+   package what should we do? */
+bool pkgExtract::HandleOverwrites(pkgFLCache::NodeIterator Nde,
+				  bool DiverCheck)
+{
+   pkgFLCache::NodeIterator TmpNde = Nde;
+   unsigned long DiverOwner = 0;
+   unsigned long FileGroup = Nde->File;
+   const char *FirstOwner = 0;
+   for (; Nde.end() == false && FileGroup == Nde->File; Nde++)
+   {
+      if ((Nde->Flags & pkgFLCache::Node::Diversion) != 0)
+      {
+	 /* Store the diversion owner if this is the forward direction
+	    of the diversion */
+	 if (DiverCheck == true)
+	    DiverOwner = Nde.Diversion()->OwnerPkg;
+	 continue;
+      }
+
+      pkgFLCache::PkgIterator FPkg(FLCache,Nde.RealPackage());	 
+      if (FPkg.end() == true || FPkg == FLPkg)
+	 continue;
+      
+      /* This tests trips when we are checking a diversion to see
+         if something has already been diverted by this diversion */
+      if (FPkg.Offset() == DiverOwner)
+	 continue;
+      FirstOwner = FPkg.Name();
+      
+      // Now see if this package matches one in a replace depends
+      pkgCache::DepIterator Dep = Ver.DependsList();
+      bool Ok = false;
+      for (; Dep.end() == false; Dep++)
+      {
+	 if (Dep->Type != pkgCache::Dep::Replaces)
+	    continue;
+	 
+	 // Does the replaces apply to this package?
+	 if (strcmp(Dep.TargetPkg().Name(),FPkg.Name()) != 0)
+	     continue;
+	 
+	 /* Check the version for match. I do not think CurrentVer can be
+	    0 if we are here.. */
+	 pkgCache::PkgIterator Pkg = Dep.TargetPkg();
+	 if (Pkg->CurrentVer == 0)
+	 {
+	    _error->Warning("Overwrite package match with no version for %s",Pkg.Name());
+	    continue;
+	 }
+
+	 // Replaces is met
+	 if (debVS.CheckDep(Pkg.CurrentVer().VerStr(),Dep->CompareOp,Dep.TargetVer()) == true)
+	 {
+	    if (Debug == true)
+	       clog << "Replaced file " << Nde.DirN() << '/' << Nde.File() << " from " << Pkg.Name() << endl;
+	    Nde->Flags |= pkgFLCache::Node::Replaced;
+	    Ok = true;
+	    break;
+	 }
+      }
+      
+      // Negative Hit
+      if (Ok == false)
+	 return _error->Error("File %s/%s overwrites the one in the package %s",
+			      Nde.DirN(),Nde.File(),FPkg.Name());
+   }
+   
+   /* If this is a diversion we might have to recurse to process
+      the other side of it */
+   if ((TmpNde->Flags & pkgFLCache::Node::Diversion) != 0)
+   {
+      pkgFLCache::DiverIterator Div = TmpNde.Diversion();
+      if (Div.DivertTo() == TmpNde)
+	 return HandleOverwrites(Div.DivertFrom(),true);
+   }
+   
+   return true;
+}
+									/*}}}*/
+// Extract::CheckDirReplace - See if this directory can be erased	/*{{{*/
+// ---------------------------------------------------------------------
+/* If this directory is owned by a single package and that package is
+   replacing it with something non-directoryish then dpkg allows this.
+   We increase the requirement to be that the directory is non-empty after
+   the package is removed */
+bool pkgExtract::CheckDirReplace(string Dir,unsigned int Depth)
+{
+   // Looping?
+   if (Depth > 40)
+      return false;
+   
+   if (Dir[Dir.size() - 1] != '/')
+      Dir += '/';
+   
+   DIR *D = opendir(Dir.c_str());
+   if (D == 0)
+      return _error->Errno("opendir","Unable to read %s",Dir.c_str());
+
+   string File;
+   for (struct dirent *Dent = readdir(D); Dent != 0; Dent = readdir(D))
+   {
+      // Skip some files
+      if (strcmp(Dent->d_name,".") == 0 ||
+	  strcmp(Dent->d_name,"..") == 0)
+	 continue;
+      
+      // Look up the node
+      File = Dir + Dent->d_name;
+      pkgFLCache::NodeIterator Nde = FLCache.GetNode(File.begin(),
+						     File.end(),0,false,false);
+
+      // The file is not owned by this package
+      if (Nde.end() != false || Nde.RealPackage() != FLPkg)
+      {
+	 closedir(D);
+	 return false;
+      }
+      
+      // See if it is a directory
+      struct stat St;
+      if (lstat(File.c_str(),&St) != 0)
+      {
+	 closedir(D);
+	 return _error->Errno("lstat","Unable to stat %s",File.c_str());
+      }
+      
+      // Recurse down directories
+      if (S_ISDIR(St.st_mode) != 0)
+      {
+	 if (CheckDirReplace(File,Depth + 1) == false)
+	 {
+	    closedir(D);
+	    return false;
+	 }
+      }      
+   }
+   
+   // No conflicts
+   closedir(D);
+   return true;
+}
+									/*}}}*/

+ 52 - 0
apt-inst/extract.h

@@ -0,0 +1,52 @@
+// -*- mode: cpp; mode: fold -*-
+// Description								/*{{{*/
+// $Id: extract.h,v 1.2 2001/02/20 07:03:16 jgg Exp $
+/* ######################################################################
+
+   Archive Extraction Directory Stream
+   
+   This Directory Stream implements extraction of an archive into the
+   filesystem. It makes the choices on what files should be unpacked and
+   replaces as well as guiding the actual unpacking.
+   
+   When the unpacking sequence is completed one of the two functions,
+   Finished or Aborted must be called.
+   
+   ##################################################################### */
+									/*}}}*/
+#ifndef PKGLIB_EXTRACT_H
+#define PKGLIB_EXTRACT_H
+
+#ifdef __GNUG__
+#pragma interface "apt-pkg/extract.h"
+#endif
+
+#include <apt-pkg/dirstream.h>
+#include <apt-pkg/filelist.h>
+#include <apt-pkg/pkgcache.h>
+
+class pkgExtract : public pkgDirStream
+{
+   pkgFLCache &FLCache;
+   pkgCache::VerIterator Ver;
+   pkgFLCache::PkgIterator FLPkg;
+   char FileName[1024];
+   bool Debug;
+   
+   bool HandleOverwrites(pkgFLCache::NodeIterator Nde,
+			 bool DiverCheck = false);
+   bool CheckDirReplace(string Dir,unsigned int Depth = 0);
+   
+   public:
+   
+   virtual bool DoItem(Item &Itm,int &Fd);
+   virtual bool Fail(Item &Itm,int Fd);
+   virtual bool FinishedFile(Item &Itm,int Fd);
+
+   bool Finished();
+   bool Aborted();
+   
+   pkgExtract(pkgFLCache &FLCache,pkgCache::VerIterator Ver);
+};
+
+#endif

+ 588 - 0
apt-inst/filelist.cc

@@ -0,0 +1,588 @@
+// -*- mode: cpp; mode: fold -*-
+// Description								/*{{{*/
+// $Id: filelist.cc,v 1.2 2001/02/20 07:03:16 jgg Exp $
+/* ######################################################################
+
+   File Listing - Manages a Cache of File -> Package names.
+
+   Diversions add some signficant complexity to the system. To keep 
+   storage space down in the very special case of a diverted file no
+   extra bytes are allocated in the Node structure. Instead a diversion
+   is inserted directly into the hash table and its flag bit set. Every
+   lookup for that filename will always return the diversion.
+   
+   The hash buckets are stored in sorted form, with diversions having 
+   the higest sort order. Identical files are assigned the same file
+   pointer, thus after a search all of the nodes owning that file can be
+   found by iterating down the bucket.
+   
+   Re-updates of diversions (another extremely special case) are done by
+   marking all diversions as untouched, then loading the entire diversion
+   list again, touching each diversion and then finally going back and
+   releasing all untouched diversions. It is assumed that the diversion
+   table will always be quite small and be a very irregular case.
+
+   Diversions that are user-installed are represented by a package with
+   an empty name string.
+
+   Conf files are handled like diversions by changing the meaning of the
+   Pointer field to point to a conf file entry - again to reduce over
+   head for a special case.
+   
+   ##################################################################### */
+									/*}}}*/
+// Include Files							/*{{{*/
+#ifdef __GNUG__
+#pragma implementation "apt-pkg/filelist.h"
+#endif
+
+#include <apt-pkg/filelist.h>
+#include <apt-pkg/mmap.h>
+#include <apt-pkg/error.h>
+#include <apt-pkg/strutl.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <iostream>
+									/*}}}*/
+
+// FlCache::Header::Header - Constructor				/*{{{*/
+// ---------------------------------------------------------------------
+/* Initialize the header variables. These are the defaults used when
+   creating new caches */
+pkgFLCache::Header::Header()
+{
+   Signature = 0xEA3F1295;
+   
+   /* Whenever the structures change the major version should be bumped,
+    whenever the generator changes the minor version should be bumped. */
+   MajorVersion = 1;
+   MinorVersion = 0;
+   Dirty = true;
+   
+   HeaderSz = sizeof(pkgFLCache::Header);
+   NodeSz = sizeof(pkgFLCache::Node);
+   DirSz = sizeof(pkgFLCache::Directory);
+   PackageSz = sizeof(pkgFLCache::Package);
+   DiversionSz = sizeof(pkgFLCache::Diversion);
+   ConfFileSz = sizeof(pkgFLCache::ConfFile);
+      
+   NodeCount = 0;
+   DirCount = 0;
+   PackageCount = 0;
+   DiversionCount = 0;
+   ConfFileCount = 0;
+   HashSize = 1 << 14;
+
+   FileHash = 0;
+   DirTree = 0;
+   Packages = 0;
+   Diversions = 0;
+   UniqNodes = 0;
+   memset(Pools,0,sizeof(Pools));
+}
+									/*}}}*/
+// FLCache::Header::CheckSizes - Check if the two headers have same *sz	/*{{{*/
+// ---------------------------------------------------------------------
+/* Compare to make sure we are matching versions */
+bool pkgFLCache::Header::CheckSizes(Header &Against) const
+{
+   if (HeaderSz == Against.HeaderSz &&
+       NodeSz == Against.NodeSz &&
+       DirSz == Against.DirSz &&
+       DiversionSz == Against.DiversionSz &&
+       PackageSz == Against.PackageSz &&
+       ConfFileSz == Against.ConfFileSz)
+            return true;
+      return false;
+}
+									/*}}}*/
+
+// FLCache::pkgFLCache - Constructor					/*{{{*/
+// ---------------------------------------------------------------------
+/* If this is a new cache then a new header and hash table are instantaited
+   otherwise the existing ones are mearly attached */
+pkgFLCache::pkgFLCache(DynamicMMap &Map) : Map(Map)
+{
+   if (_error->PendingError() == true)
+      return;
+
+   LastTreeLookup = 0;
+   LastLookupSize = 0;
+   
+   // Apply the typecasts
+   HeaderP = (Header *)Map.Data();
+   NodeP = (Node *)Map.Data();
+   DirP = (Directory *)Map.Data();
+   DiverP = (Diversion *)Map.Data();
+   PkgP = (Package *)Map.Data();
+   ConfP = (ConfFile *)Map.Data();
+   StrP = (char *)Map.Data();
+   AnyP = (unsigned char *)Map.Data();
+   
+   // New mapping, create the basic cache structures
+   if (Map.Size() == 0)
+   {
+      Map.RawAllocate(sizeof(pkgFLCache::Header));
+      *HeaderP = pkgFLCache::Header();
+      HeaderP->FileHash = Map.RawAllocate(sizeof(pkgFLCache::Node)*HeaderP->HashSize,
+					  sizeof(pkgFLCache::Node))/sizeof(pkgFLCache::Node);
+   }
+
+   FileHash = NodeP + HeaderP->FileHash;
+   
+   // Setup the dynamic map manager
+   HeaderP->Dirty = true;
+   Map.Sync(0,sizeof(pkgFLCache::Header));
+   Map.UsePools(*HeaderP->Pools,sizeof(HeaderP->Pools)/sizeof(HeaderP->Pools[0]));
+}
+									/*}}}*/
+// FLCache::TreeLookup - Perform a lookup in a generic tree		/*{{{*/
+// ---------------------------------------------------------------------
+/* This is a simple generic tree lookup. The first three entries of
+   the Directory structure are used as a template, but any other similar
+   structure could be used in it's place. */
+map_ptrloc pkgFLCache::TreeLookup(map_ptrloc *Base,const char *Text,
+				  const char *TextEnd,unsigned long Size,
+				  unsigned int *Count,bool Insert)
+{       
+   pkgFLCache::Directory *Dir;
+   
+   // Check our last entry cache
+   if (LastTreeLookup != 0 && LastLookupSize == Size)
+   {
+      Dir = (pkgFLCache::Directory *)(AnyP + LastTreeLookup*Size);
+      if (stringcmp(Text,TextEnd,StrP + Dir->Name) == 0)
+	 return LastTreeLookup; 
+   }   
+   
+   while (1)
+   {
+      // Allocate a new one
+      if (*Base == 0)
+      {
+	 if (Insert == false)
+	    return 0;
+	 
+	 *Base = Map.Allocate(Size);
+	 if (*Base == 0)
+	    return 0;
+	 
+	 (*Count)++;
+	 Dir = (pkgFLCache::Directory *)(AnyP + *Base*Size);
+	 Dir->Name = Map.WriteString(Text,TextEnd - Text);
+	 LastTreeLookup = *Base;
+	 LastLookupSize = Size;
+	 return *Base;
+      }
+      
+      // Compare this node
+      Dir = (pkgFLCache::Directory *)(AnyP + *Base*Size);
+      int Res = stringcmp(Text,TextEnd,StrP + Dir->Name);
+      if (Res == 0)
+      {
+	 LastTreeLookup = *Base;
+	 LastLookupSize = Size;
+	 return *Base;
+      }
+      
+      if (Res > 0)
+	 Base = &Dir->Left;
+      if (Res < 0)
+	 Base = &Dir->Right;
+   }
+}
+									/*}}}*/
+// FLCache::PrintTree - Print out a tree				/*{{{*/
+// ---------------------------------------------------------------------
+/* This is a simple generic tree dumper, ment for debugging. */
+void pkgFLCache::PrintTree(map_ptrloc Base,unsigned long Size)
+{
+   if (Base == 0)
+      return;
+   
+   pkgFLCache::Directory *Dir = (pkgFLCache::Directory *)(AnyP + Base*Size);
+   PrintTree(Dir->Left,Size);
+   cout << (StrP + Dir->Name) << endl;
+   PrintTree(Dir->Right,Size);
+}
+									/*}}}*/
+// FLCache::GetPkg - Get a package pointer				/*{{{*/
+// ---------------------------------------------------------------------
+/* Locate a package by name in it's tree, this is just a wrapper for
+   TreeLookup */
+pkgFLCache::PkgIterator pkgFLCache::GetPkg(const char *Name,const char *NameEnd,
+					   bool Insert)
+{
+   if (NameEnd == 0)
+      NameEnd = Name + strlen(Name);
+   
+   map_ptrloc Pos = TreeLookup(&HeaderP->Packages,Name,NameEnd,
+			       sizeof(pkgFLCache::Package),
+			       &HeaderP->PackageCount,Insert);
+   if (Pos == 0)
+      return pkgFLCache::PkgIterator();
+   return pkgFLCache::PkgIterator(*this,PkgP + Pos);
+}
+									/*}}}*/
+// FLCache::GetNode - Get the node associated with the filename		/*{{{*/
+// ---------------------------------------------------------------------
+/* Lookup a node in the hash table. If Insert is true then a new node is
+   always inserted. The hash table can have multiple instances of a
+   single name available. A search returns the first. It is important
+   that additions for the same name insert after the first entry of
+   the name group. */
+pkgFLCache::NodeIterator pkgFLCache::GetNode(const char *Name,
+					     const char *NameEnd,
+					     map_ptrloc Loc,
+					     bool Insert,bool Divert)
+{
+   // Split the name into file and directory, hashing as it is copied 
+   const char *File = Name;
+   unsigned long HashPos = 0;
+   for (const char *I = Name; I < NameEnd; I++)
+   {
+      HashPos = 1637*HashPos + *I;
+      if (*I == '/')
+	 File = I;
+   }
+   
+   // Search for it
+   Node *Hash = NodeP + HeaderP->FileHash + (HashPos % HeaderP->HashSize);
+   int Res = 0;
+   map_ptrloc FilePtr = 0;
+   while (Hash->Pointer != 0)
+   {
+      // Compare
+      Res = stringcmp(File+1,NameEnd,StrP + Hash->File);
+      if (Res == 0)
+	 Res = stringcmp(Name,File,StrP + DirP[Hash->Dir].Name);
+      
+      // Diversion?
+      if (Res == 0 && Insert == true)
+      {
+	 /* Dir and File match exactly, we need to reuse the file name
+	    when we link it in */
+	 FilePtr = Hash->File;
+	 Res = Divert - ((Hash->Flags & Node::Diversion) == Node::Diversion);
+      }
+      
+      // Is a match
+      if (Res == 0)
+      {
+	 if (Insert == false)
+	    return NodeIterator(*this,Hash);
+	 
+	 // Only one diversion per name!
+	 if (Divert == true)
+	    return NodeIterator(*this,Hash);
+	 break;
+      }
+            
+      // Out of sort order
+      if (Res > 0)
+	 break;
+      
+      if (Hash->Next != 0)
+	 Hash = NodeP + Hash->Next;
+      else
+	 break;
+   }   
+   
+   // Fail, not found
+   if (Insert == false)
+      return NodeIterator(*this);
+
+   // Find a directory node
+   map_ptrloc Dir = TreeLookup(&HeaderP->DirTree,Name,File,
+			       sizeof(pkgFLCache::Directory),
+			       &HeaderP->DirCount,true);
+   if (Dir == 0)
+      return NodeIterator(*this);
+
+   // Allocate a new node
+   if (Hash->Pointer != 0)
+   {
+      // Overwrite or append
+      if (Res > 0)
+      {
+	 Node *Next = NodeP + Map.Allocate(sizeof(*Hash));
+	 if (Next == NodeP)
+	    return NodeIterator(*this);
+	 *Next = *Hash;
+	 Hash->Next = Next - NodeP;
+      }
+      else
+      {
+	 unsigned long NewNext = Map.Allocate(sizeof(*Hash));
+	 if (NewNext == 0)
+	    return NodeIterator(*this);
+	 NodeP[NewNext].Next = Hash->Next;
+	 Hash->Next = NewNext;
+	 Hash = NodeP + Hash->Next;
+      }      
+   }      
+   
+   // Insert into the new item
+   Hash->Dir = Dir;
+   Hash->Pointer = Loc;
+   Hash->Flags = 0;
+   if (Divert == true)
+      Hash->Flags |= Node::Diversion;
+   
+   if (FilePtr != 0)
+      Hash->File = FilePtr;
+   else
+   {
+      HeaderP->UniqNodes++;
+      Hash->File = Map.WriteString(File+1,NameEnd - File-1);
+   }
+   
+   // Link the node to the package list
+   if (Divert == false && Loc == 0)
+   {
+      Hash->Next = PkgP[Loc].Files;
+      PkgP[Loc].Files = Hash - NodeP;
+   }
+   
+   HeaderP->NodeCount++;
+   return NodeIterator(*this,Hash);
+}
+									/*}}}*/
+// FLCache::HashNode - Return the hash bucket for the node		/*{{{*/
+// ---------------------------------------------------------------------
+/* This is one of two hashing functions. The other is inlined into the
+   GetNode routine. */
+pkgFLCache::Node *pkgFLCache::HashNode(NodeIterator const &Nde)
+{
+   // Hash the node
+   unsigned long HashPos = 0;
+   for (const char *I = Nde.DirN(); *I != 0; I++)
+      HashPos = 1637*HashPos + *I;
+   HashPos = 1637*HashPos + '/';
+   for (const char *I = Nde.File(); *I != 0; I++)
+      HashPos = 1637*HashPos + *I;
+   return NodeP + HeaderP->FileHash + (HashPos % HeaderP->HashSize);
+}
+									/*}}}*/
+// FLCache::DropNode - Drop a node from the hash table			/*{{{*/
+// ---------------------------------------------------------------------
+/* This erases a node from the hash table. Note that this does not unlink
+   the node from the package linked list. */
+void pkgFLCache::DropNode(map_ptrloc N)
+{
+   if (N == 0)
+      return;
+   
+   NodeIterator Nde(*this,NodeP + N);
+   
+   if (Nde->NextPkg != 0)
+      _error->Warning("DropNode called on still linked node");
+   
+   // Locate it in the hash table
+   Node *Last = 0;
+   Node *Hash = HashNode(Nde);
+   while (Hash->Pointer != 0)
+   {
+      // Got it
+      if (Hash == Nde)
+      {
+	 // Top of the bucket..
+	 if (Last == 0)
+	 {
+	    Hash->Pointer = 0;
+	    if (Hash->Next == 0)
+	       return;
+	    *Hash = NodeP[Hash->Next];
+	    // Release Hash->Next
+	    return;
+	 }
+	 Last->Next = Hash->Next;
+	 // Release Hash
+	 return;
+      }
+      
+      Last = Hash;
+      if (Hash->Next != 0)
+	 Hash = NodeP + Hash->Next;
+      else
+	 break;
+   }   
+ 
+   _error->Error("Failed to locate the hash element!");
+}
+									/*}}}*/
+// FLCache::BeginDiverLoad - Start reading new diversions		/*{{{*/
+// ---------------------------------------------------------------------
+/* Tag all the diversions as untouched */
+void pkgFLCache::BeginDiverLoad()
+{
+   for (DiverIterator I = DiverBegin(); I.end() == false; I++)
+      I->Flags = 0;
+}
+									/*}}}*/
+// FLCache::FinishDiverLoad - Finish up a new diversion load		/*{{{*/
+// ---------------------------------------------------------------------
+/* This drops any untouched diversions. In effect removing any diversions
+   that where not loaded (ie missing from the diversion file) */
+void pkgFLCache::FinishDiverLoad()
+{
+   map_ptrloc *Cur = &HeaderP->Diversions;
+   while (*Cur != 0) 
+   {
+      Diversion *Div = DiverP + *Cur;
+      if ((Div->Flags & Diversion::Touched) == Diversion::Touched)
+      {
+	 Cur = &Div->Next;
+	 continue;
+      }
+   
+      // Purge!
+      DropNode(Div->DivertTo);
+      DropNode(Div->DivertFrom);
+      *Cur = Div->Next;
+   }
+}
+									/*}}}*/
+// FLCache::AddDiversion - Add a new diversion				/*{{{*/
+// ---------------------------------------------------------------------
+/* Add a new diversion to the diverion tables and make sure that it is
+   unique and non-chaining. */
+bool pkgFLCache::AddDiversion(PkgIterator const &Owner,
+			      const char *From,const char *To)
+{   
+   /* Locate the two hash nodes we are going to manipulate. If there
+      are pre-existing diversions then they will be returned */
+   NodeIterator FromN = GetNode(From,From+strlen(From),0,true,true);
+   NodeIterator ToN = GetNode(To,To+strlen(To),0,true,true);
+   if (FromN.end() == true || ToN.end() == true)
+      return _error->Error("Failed to allocate diversion");
+
+   // Should never happen
+   if ((FromN->Flags & Node::Diversion) != Node::Diversion ||
+       (ToN->Flags & Node::Diversion) != Node::Diversion)
+      return _error->Error("Internal Error in AddDiversion");
+
+   // Now, try to reclaim an existing diversion..
+   map_ptrloc Diver = 0;
+   if (FromN->Pointer != 0)
+      Diver = FromN->Pointer;
+  
+   /* Make sure from and to point to the same diversion, if they dont
+      then we are trying to intermix diversions - very bad */
+   if (ToN->Pointer != 0 && ToN->Pointer != Diver)
+   {
+      // It could be that the other diversion is no longer in use
+      if ((DiverP[ToN->Pointer].Flags & Diversion::Touched) == Diversion::Touched)	 
+	 return _error->Error("Trying to overwrite a diversion, %s -> %s and %s/%s",
+			      From,To,ToN.File(),ToN.Dir().Name());
+      
+      // We can erase it.
+      Diversion *Div = DiverP + ToN->Pointer;
+      ToN->Pointer = 0;
+      
+      if (Div->DivertTo == ToN.Offset())
+	 Div->DivertTo = 0;
+      if (Div->DivertFrom == ToN.Offset())
+	 Div->DivertFrom = 0;
+      
+      // This diversion will be cleaned up by FinishDiverLoad
+   }
+   
+   // Allocate a new diversion
+   if (Diver == 0)
+   {
+      Diver = Map.Allocate(sizeof(Diversion));
+      if (Diver == 0)
+	 return false;
+      DiverP[Diver].Next = HeaderP->Diversions;
+      HeaderP->Diversions = Diver;
+      HeaderP->DiversionCount++;
+   }
+
+   // Can only have one diversion of the same files
+   Diversion *Div = DiverP + Diver;
+   if ((Div->Flags & Diversion::Touched) == Diversion::Touched)
+      return _error->Error("Double add of diversion %s -> %s",From,To);
+   
+   // Setup the From/To links
+   if (Div->DivertFrom != FromN.Offset() && Div->DivertFrom != ToN.Offset())
+      DropNode(Div->DivertFrom);
+   Div->DivertFrom = FromN.Offset();
+   if (Div->DivertTo != FromN.Offset() && Div->DivertTo != ToN.Offset())
+      DropNode(Div->DivertTo);
+   Div->DivertTo = ToN.Offset();
+   
+   // Link it to the two nodes
+   FromN->Pointer = Diver;
+   ToN->Pointer = Diver;
+   
+   // And the package
+   Div->OwnerPkg = Owner.Offset();
+   Div->Flags |= Diversion::Touched;
+   
+   return true;
+}
+									/*}}}*/
+// FLCache::AddConfFile - Add a new configuration file			/*{{{*/
+// ---------------------------------------------------------------------
+/* This simply adds a new conf file node to the hash table. This is only
+   used by the status file reader. It associates a hash with each conf
+   file entry that exists in the status file and the list file for 
+   the proper package. Duplicate conf files (across packages) are left
+   up to other routines to deal with. */
+bool pkgFLCache::AddConfFile(const char *Name,const char *NameEnd,
+			     PkgIterator const &Owner,
+			     const unsigned char *Sum)
+{
+   NodeIterator Nde = GetNode(Name,NameEnd,0,false,false);
+   if (Nde.end() == true)
+      return true;
+   
+   unsigned long File = Nde->File;
+   for (; Nde->File == File && Nde.end() == false; Nde++)
+   {
+      if (Nde.RealPackage() != Owner)
+	 continue;
+
+      if ((Nde->Flags & Node::ConfFile) == Node::ConfFile)
+	 return _error->Error("Duplicate conf file %s/%s",Nde.DirN(),Nde.File());
+			      
+      // Allocate a new conf file structure
+      map_ptrloc Conf = Map.Allocate(sizeof(ConfFile));
+      if (Conf == 0)
+	 return false;
+      ConfP[Conf].OwnerPkg = Owner.Offset();
+      memcpy(ConfP[Conf].MD5,Sum,sizeof(ConfP[Conf].MD5));
+      
+      Nde->Pointer = Conf;
+      Nde->Flags |= Node::ConfFile;
+      return true;
+   }
+      
+   /* This means the conf file has been replaced, but the entry in the 
+      status file was not updated */
+   return true;
+}
+									/*}}}*/
+
+// NodeIterator::RealPackage - Return the package for this node		/*{{{*/
+// ---------------------------------------------------------------------
+/* Since the package pointer is indirected in all sorts of interesting ways
+   this is used to get a pointer to the owning package */
+pkgFLCache::Package *pkgFLCache::NodeIterator::RealPackage() const
+{
+   if (Nde->Pointer == 0)
+      return 0;
+   
+   if ((Nde->Flags & Node::ConfFile) == Node::ConfFile)
+      return Owner->PkgP + Owner->ConfP[Nde->Pointer].OwnerPkg;
+
+   // Diversions are ignored
+   if ((Nde->Flags & Node::Diversion) == Node::Diversion)
+      return 0;
+   
+   return Owner->PkgP + Nde->Pointer;
+}
+									/*}}}*/

+ 314 - 0
apt-inst/filelist.h

@@ -0,0 +1,314 @@
+// -*- mode: cpp; mode: fold -*-
+// Description								/*{{{*/
+// $Id: filelist.h,v 1.2 2001/02/20 07:03:16 jgg Exp $
+/* ######################################################################
+
+   File Listing - Manages a Cache of File -> Package names.
+
+   This is identical to the Package cache, except that the generator 
+   (which is much simpler) is integrated directly into the main class, 
+   and it has been designed to handle live updates.
+   
+   The storage content of the class is maintained in a memory map and is
+   written directly to the file system. Performance is traded against 
+   space to give something that performs well and remains small.
+   The average per file usage is 32 bytes which yeilds about a meg every
+   36k files. Directory paths are collected into a binary tree and stored
+   only once, this offsets the cost of the hash nodes enough to keep 
+   memory usage slightly less than the sum of the filenames.
+ 
+   The file names are stored into a fixed size chained hash table that is
+   linked to the package name and to the directory component. 
+
+   Each file node has a set of associated flags that indicate the current
+   state of the file.
+   
+   ##################################################################### */
+									/*}}}*/
+#ifndef PKGLIB_FILELIST_H
+#define PKGLIB_FILELIST_H
+
+#ifdef __GNUG__
+#pragma interface "apt-pkg/filelist.h"
+#endif
+
+#include <apt-pkg/mmap.h>
+
+class pkgFLCache
+{
+   public:
+   struct Header;
+   struct Node;
+   struct Directory;
+   struct Package;
+   struct Diversion;
+   struct ConfFile;
+   
+   class NodeIterator;
+   class DirIterator;
+   class PkgIterator;
+   class DiverIterator;
+   
+   protected:
+   string CacheFile;
+   DynamicMMap &Map;
+   map_ptrloc LastTreeLookup;
+   unsigned long LastLookupSize;
+   
+   // Helpers for the addition algorithms
+   map_ptrloc TreeLookup(map_ptrloc *Base,const char *Text,const char *TextEnd,
+			 unsigned long Size,unsigned int *Count = 0,
+			 bool Insert = false);
+   
+   public:
+   
+   // Pointers to the arrays of items
+   Header *HeaderP;
+   Node *NodeP;
+   Directory *DirP;
+   Package *PkgP;
+   Diversion *DiverP;
+   ConfFile *ConfP;
+   char *StrP;
+   unsigned char *AnyP;
+   
+   // Quick accessors
+   Node *FileHash;
+   
+   // Accessors
+   Header &Head() {return *HeaderP;};
+   void PrintTree(map_ptrloc Base,unsigned long Size);
+
+   // Add/Find things
+   PkgIterator GetPkg(const char *Name,const char *End,bool Insert);
+   inline PkgIterator GetPkg(const char *Name,bool Insert);
+   NodeIterator GetNode(const char *Name,
+			const char *NameEnd,
+			map_ptrloc Loc,
+			bool Insert,bool Divert);
+   Node *HashNode(NodeIterator const &N);
+   void DropNode(map_ptrloc Node);
+
+   inline DiverIterator DiverBegin();
+   
+   // Diversion control
+   void BeginDiverLoad();
+   void FinishDiverLoad();
+   bool AddDiversion(PkgIterator const &Owner,const char *From,
+		     const char *To);
+   bool AddConfFile(const char *Name,const char *NameEnd,
+		    PkgIterator const &Owner,const unsigned char *Sum);
+			     
+   pkgFLCache(DynamicMMap &Map);
+//   ~pkgFLCache();
+};
+
+struct pkgFLCache::Header
+{
+   // Signature information
+   unsigned long Signature;
+   short MajorVersion;
+   short MinorVersion;
+   bool Dirty;
+   
+   // Size of structure values
+   unsigned HeaderSz;
+   unsigned NodeSz;
+   unsigned DirSz;
+   unsigned PackageSz;
+   unsigned DiversionSz;
+   unsigned ConfFileSz;
+   
+   // Structure Counts;
+   unsigned int NodeCount;
+   unsigned int DirCount;
+   unsigned int PackageCount;
+   unsigned int DiversionCount;
+   unsigned int ConfFileCount;
+   unsigned int HashSize;
+   unsigned long UniqNodes;
+      
+   // Offsets
+   map_ptrloc FileHash;
+   map_ptrloc DirTree;
+   map_ptrloc Packages;
+   map_ptrloc Diversions;
+      
+   /* Allocation pools, there should be one of these for each structure
+      excluding the header */
+   DynamicMMap::Pool Pools[5];
+
+   bool CheckSizes(Header &Against) const;
+   Header();
+};
+
+/* The bit field is used to advoid incurring an extra 4 bytes x 40000,
+   Pointer is the most infrequently used member of the structure */
+struct pkgFLCache::Node
+{
+   map_ptrloc Dir;            // Dir
+   map_ptrloc File;           // String
+   unsigned Pointer:24;       // Package/Diversion/ConfFile
+   unsigned Flags:8;          // Package
+   map_ptrloc Next;           // Node
+   map_ptrloc NextPkg;        // Node
+
+   enum Flags {Diversion = (1<<0),ConfFile = (1<<1),
+               NewConfFile = (1<<2),NewFile = (1<<3),
+               Unpacked = (1<<4),Replaced = (1<<5)};
+};
+
+struct pkgFLCache::Directory
+{
+   map_ptrloc Left;           // Directory
+   map_ptrloc Right;          // Directory
+   map_ptrloc Name;           // String
+};
+
+struct pkgFLCache::Package
+{
+   map_ptrloc Left;           // Package
+   map_ptrloc Right;          // Package
+   map_ptrloc Name;           // String
+   map_ptrloc Files;          // Node
+};
+
+struct pkgFLCache::Diversion
+{
+   map_ptrloc OwnerPkg;       // Package
+   map_ptrloc DivertFrom;     // Node
+   map_ptrloc DivertTo;       // String
+   
+   map_ptrloc Next;           // Diversion
+   unsigned long Flags;
+
+   enum Flags {Touched = (1<<0)};
+};
+
+struct pkgFLCache::ConfFile
+{
+   map_ptrloc OwnerPkg;       // Package
+   unsigned char MD5[16];
+};
+
+class pkgFLCache::PkgIterator
+{
+   Package *Pkg;
+   pkgFLCache *Owner;
+   
+   public:
+   
+   inline bool end() const {return Owner == 0 || Pkg == Owner->PkgP?true:false;}
+   
+   // Accessors
+   inline Package *operator ->() {return Pkg;};
+   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 const *() const {return Pkg == Owner->PkgP?0:Pkg;};
+
+   inline unsigned long Offset() const {return Pkg - Owner->PkgP;};
+   inline const char *Name() const {return Pkg->Name == 0?0:Owner->StrP + Pkg->Name;};
+   inline pkgFLCache::NodeIterator Files() const;
+
+   PkgIterator() : Pkg(0), Owner(0) {};
+   PkgIterator(pkgFLCache &Owner,Package *Trg) : Pkg(Trg), Owner(&Owner) {};
+};
+
+class pkgFLCache::DirIterator
+{
+   Directory *Dir;
+   pkgFLCache *Owner;
+   
+   public:
+   
+   // Accessors
+   inline Directory *operator ->() {return Dir;};
+   inline Directory const *operator ->() const {return Dir;};
+   inline Directory const &operator *() const {return *Dir;};
+   inline operator Directory *() {return Dir == Owner->DirP?0:Dir;};
+   inline operator Directory const *() const {return Dir == Owner->DirP?0:Dir;};
+
+   inline const char *Name() const {return Dir->Name == 0?0:Owner->StrP + Dir->Name;};
+
+   DirIterator() : Dir(0), Owner(0) {};
+   DirIterator(pkgFLCache &Owner,Directory *Trg) : Dir(Trg), Owner(&Owner) {};
+};
+
+class pkgFLCache::DiverIterator
+{
+   Diversion *Diver;
+   pkgFLCache *Owner;
+   
+   public:
+
+   // Iteration
+   void operator ++(int) {if (Diver != Owner->DiverP) Diver = Owner->DiverP + Diver->Next;};
+   inline void operator ++() {operator ++(0);};
+   inline bool end() const {return Owner == 0 || Diver == Owner->DiverP;};
+
+   // Accessors
+   inline Diversion *operator ->() {return Diver;};
+   inline Diversion const *operator ->() const {return Diver;};
+   inline Diversion const &operator *() const {return *Diver;};
+   inline operator Diversion *() {return Diver == Owner->DiverP?0:Diver;};
+   inline operator Diversion const *() const {return Diver == Owner->DiverP?0:Diver;};
+
+   inline PkgIterator OwnerPkg() const {return PkgIterator(*Owner,Owner->PkgP + Diver->OwnerPkg);};
+   inline NodeIterator DivertFrom() const;
+   inline NodeIterator DivertTo() const;
+
+   DiverIterator() : Diver(0), Owner(0) {};
+   DiverIterator(pkgFLCache &Owner,Diversion *Trg) : Diver(Trg), Owner(&Owner) {};
+};
+
+class pkgFLCache::NodeIterator
+{
+   Node *Nde;
+   enum {NdePkg, NdeHash} Type;   
+   pkgFLCache *Owner;
+   
+   public:
+   
+   // Iteration
+   void operator ++(int) {if (Nde != Owner->NodeP) Nde = Owner->NodeP + 
+	 (Type == NdePkg?Nde->NextPkg:Nde->Next);};
+   inline void operator ++() {operator ++(0);};
+   inline bool end() const {return Owner == 0 || Nde == Owner->NodeP;};
+
+   // Accessors
+   inline Node *operator ->() {return Nde;};
+   inline Node const *operator ->() const {return Nde;};
+   inline Node const &operator *() const {return *Nde;};
+   inline operator Node *() {return Nde == Owner->NodeP?0:Nde;};
+   inline operator Node const *() const {return Nde == Owner->NodeP?0:Nde;};
+   inline unsigned long Offset() const {return Nde - Owner->NodeP;};
+   inline DirIterator Dir() const {return DirIterator(*Owner,Owner->DirP + Nde->Dir);};
+   inline DiverIterator Diversion() const {return DiverIterator(*Owner,Owner->DiverP + Nde->Pointer);};
+   inline const char *File() const {return Nde->File == 0?0:Owner->StrP + Nde->File;};
+   inline const char *DirN() const {return Owner->StrP + Owner->DirP[Nde->Dir].Name;};
+   Package *RealPackage() const;
+   
+   NodeIterator() : Nde(0), Type(NdeHash), Owner(0) {};
+   NodeIterator(pkgFLCache &Owner) : Nde(Owner.NodeP), Type(NdeHash), Owner(&Owner) {};
+   NodeIterator(pkgFLCache &Owner,Node *Trg) : Nde(Trg), Type(NdeHash), Owner(&Owner) {};
+   NodeIterator(pkgFLCache &Owner,Node *Trg,Package *) : Nde(Trg), Type(NdePkg), Owner(&Owner) {};
+};
+
+/* Inlines with forward references that cannot be included directly in their
+   respsective classes */
+inline pkgFLCache::NodeIterator pkgFLCache::DiverIterator::DivertFrom() const 
+   {return NodeIterator(*Owner,Owner->NodeP + Diver->DivertFrom);};
+inline pkgFLCache::NodeIterator pkgFLCache::DiverIterator::DivertTo() const
+   {return NodeIterator(*Owner,Owner->NodeP + Diver->DivertTo);};
+
+inline pkgFLCache::NodeIterator pkgFLCache::PkgIterator::Files() const
+   {return NodeIterator(*Owner,Owner->NodeP + Pkg->Files,Pkg);};
+
+inline pkgFLCache::DiverIterator pkgFLCache::DiverBegin()
+   {return DiverIterator(*this,DiverP + HeaderP->Diversions);};
+
+inline pkgFLCache::PkgIterator pkgFLCache::GetPkg(const char *Name,bool Insert) 
+   {return GetPkg(Name,Name+strlen(Name),Insert);};
+
+#endif

+ 30 - 0
apt-inst/makefile

@@ -0,0 +1,30 @@
+# -*- make -*-
+BASE=..
+SUBDIR=apt-inst
+
+# Header location
+SUBDIRS = contrib deb
+HEADER_TARGETDIRS = apt-pkg
+
+# Bring in the default rules
+include ../buildlib/defaults.mak
+
+# The library name
+LIBRARY=apt-inst
+MAJOR=1.0
+MINOR=0
+SLIBS=$(PTHREADLIB)
+
+# Source code for the contributed non-core things
+SOURCE = contrib/extracttar.cc contrib/arfile.cc
+
+# Source code for the main library
+SOURCE+= filelist.cc database.cc dirstream.cc extract.cc \
+         deb/dpkgdb.cc deb/debfile.cc
+
+# Public header files
+HEADERS = extracttar.h arfile.h filelist.h database.h extract.h \
+          dpkgdb.h dirstream.h debfile.h
+
+HEADERS := $(addprefix apt-pkg/,$(HEADERS))
+include $(LIBRARY_H)

+ 82 - 60
apt-pkg/acquire-item.cc

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: acquire-item.cc,v 1.41 2000/01/17 07:11:49 jgg Exp $
+// $Id: acquire-item.cc,v 1.42 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
 
    Acquire Item - Item to acquire
@@ -18,10 +18,13 @@
 #endif
 #include <apt-pkg/acquire-item.h>
 #include <apt-pkg/configuration.h>
+#include <apt-pkg/sourcelist.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/strutl.h>
 #include <apt-pkg/fileutl.h>
 
+#include <apti18n.h>
+    
 #include <sys/stat.h>
 #include <unistd.h>
 #include <errno.h>
@@ -116,7 +119,7 @@ void pkgAcquire::Item::Rename(string From,string To)
    if (rename(From.c_str(),To.c_str()) != 0)
    {
       char S[300];
-      sprintf(S,"rename failed, %s (%s -> %s).",strerror(errno),
+      sprintf(S,_("rename failed, %s (%s -> %s)."),strerror(errno),
 	      From.c_str(),To.c_str());
       Status = StatError;
       ErrorText = S;
@@ -127,31 +130,24 @@ void pkgAcquire::Item::Rename(string From,string To)
 // AcqIndex::AcqIndex - Constructor					/*{{{*/
 // ---------------------------------------------------------------------
 /* The package file is added to the queue and a second class is 
-   instantiated to fetch the revision file */
-pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner,const pkgSourceList::Item *Location) :
-             Item(Owner), Location(Location)
+   instantiated to fetch the revision file */   
+pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner,
+			 string URI,string URIDesc,string ShortDesc) :
+                      Item(Owner), RealURI(URI)
 {
    Decompression = false;
    Erase = false;
    
    DestFile = _config->FindDir("Dir::State::lists") + "partial/";
-   DestFile += URItoFileName(Location->PackagesURI());
+   DestFile += URItoFileName(URI);
 
    // Create the item
-   Desc.URI = Location->PackagesURI() + ".gz";
-   Desc.Description = Location->PackagesInfo();
+   Desc.URI = URI + ".gz";
+   Desc.Description = URIDesc;
    Desc.Owner = this;
-
-   // Set the short description to the archive component
-   if (Location->Dist[Location->Dist.size() - 1] == '/')
-      Desc.ShortDesc = Location->Dist;
-   else
-      Desc.ShortDesc = Location->Dist + '/' + Location->Section;  
+   Desc.ShortDesc = ShortDesc;
       
    QueueURI(Desc);
-   
-   // Create the Release fetch class
-   new pkgAcqIndexRel(Owner,Location);
 }
 									/*}}}*/
 // AcqIndex::Custom600Headers - Insert custom request headers		/*{{{*/
@@ -160,7 +156,7 @@ pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner,const pkgSourceList::Item *Location)
 string pkgAcqIndex::Custom600Headers()
 {
    string Final = _config->FindDir("Dir::State::lists");
-   Final += URItoFileName(Location->PackagesURI());
+   Final += URItoFileName(RealURI);
    
    struct stat Buf;
    if (stat(Final.c_str(),&Buf) != 0)
@@ -185,13 +181,13 @@ void pkgAcqIndex::Done(string Message,unsigned long Size,string MD5,
    {
       // Done, move it into position
       string FinalFile = _config->FindDir("Dir::State::lists");
-      FinalFile += URItoFileName(Location->PackagesURI());
+      FinalFile += URItoFileName(RealURI);
       Rename(DestFile,FinalFile);
       
       /* We restore the original name to DestFile so that the clean operation
          will work OK */
       DestFile = _config->FindDir("Dir::State::lists") + "partial/";
-      DestFile += URItoFileName(Location->PackagesURI());
+      DestFile += URItoFileName(RealURI);
       
       // Remove the compressed version.
       if (Erase == true)
@@ -237,7 +233,7 @@ void pkgAcqIndex::Done(string Message,unsigned long Size,string MD5,
    
    Decompression = true;
    DestFile += ".decomp";
-   Desc.URI = "gzip:" + FileName,Location->PackagesInfo();
+   Desc.URI = "gzip:" + FileName;
    QueueURI(Desc);
    Mode = "gzip";
 }
@@ -247,23 +243,18 @@ void pkgAcqIndex::Done(string Message,unsigned long Size,string MD5,
 // ---------------------------------------------------------------------
 /* The Release file is added to the queue */
 pkgAcqIndexRel::pkgAcqIndexRel(pkgAcquire *Owner,
-			       const pkgSourceList::Item *Location) :
-                Item(Owner), Location(Location)
+			    string URI,string URIDesc,string ShortDesc) :
+                      Item(Owner), RealURI(URI)
 {
    DestFile = _config->FindDir("Dir::State::lists") + "partial/";
-   DestFile += URItoFileName(Location->ReleaseURI());
+   DestFile += URItoFileName(URI);
    
    // Create the item
-   Desc.URI = Location->ReleaseURI();
-   Desc.Description = Location->ReleaseInfo();
+   Desc.URI = URI;
+   Desc.Description = URIDesc;
+   Desc.ShortDesc = ShortDesc;
    Desc.Owner = this;
 
-   // Set the short description to the archive component
-   if (Location->Dist[Location->Dist.size() - 1] == '/')
-      Desc.ShortDesc = Location->Dist;
-   else
-      Desc.ShortDesc = Location->Dist + '/' + Location->Section;  
-      
    QueueURI(Desc);
 }
 									/*}}}*/
@@ -273,7 +264,7 @@ pkgAcqIndexRel::pkgAcqIndexRel(pkgAcquire *Owner,
 string pkgAcqIndexRel::Custom600Headers()
 {
    string Final = _config->FindDir("Dir::State::lists");
-   Final += URItoFileName(Location->ReleaseURI());
+   Final += URItoFileName(RealURI);
    
    struct stat Buf;
    if (stat(Final.c_str(),&Buf) != 0)
@@ -317,7 +308,7 @@ void pkgAcqIndexRel::Done(string Message,unsigned long Size,string MD5,
    
    // Done, move it into position
    string FinalFile = _config->FindDir("Dir::State::lists");
-   FinalFile += URItoFileName(Location->ReleaseURI());
+   FinalFile += URItoFileName(RealURI);
    Rename(DestFile,FinalFile);
 }
 									/*}}}*/
@@ -354,21 +345,42 @@ pkgAcqArchive::pkgAcqArchive(pkgAcquire *Owner,pkgSourceList *Sources,
 
    if (Version.Arch() == 0)
    {
-      _error->Error("I wasn't able to locate file for the %s package. "
-		    "This might mean you need to manually fix this package. (due to missing arch)",
+      _error->Error(_("I wasn't able to locate file for the %s package. "
+		    "This might mean you need to manually fix this package. (due to missing arch)"),
 		    Version.ParentPkg().Name());
       return;
    }
    
-   // Generate the final file name as: package_version_arch.deb
-   StoreFilename = QuoteString(Version.ParentPkg().Name(),"_:") + '_' +
-                   QuoteString(Version.VerStr(),"_:") + '_' +
-                   QuoteString(Version.Arch(),"_:.") + ".deb";
-
+   /* We need to find a filename to determine the extension. We make the
+      assumption here that all the available sources for this version share
+      the same extension.. */
+   // Skip not source sources, they do not have file fields.
+   for (; Vf.end() == false; Vf++)
+   {
+      if ((Vf.File()->Flags & pkgCache::Flag::NotSource) != 0)
+	 continue;
+      break;
+   }
+   
+   // Does not really matter here.. we are going to fail out below
+   if (Vf.end() != true)
+   {     
+      // If this fails to get a file name we will bomb out below.
+      pkgRecords::Parser &Parse = Recs->Lookup(Vf);
+      if (_error->PendingError() == true)
+	 return;
+            
+      // Generate the final file name as: package_version_arch.foo
+      StoreFilename = QuoteString(Version.ParentPkg().Name(),"_:") + '_' +
+	              QuoteString(Version.VerStr(),"_:") + '_' +
+     	              QuoteString(Version.Arch(),"_:.") + 
+	              "." + flExtension(Parse.FileName());
+   }
+      
    // Select a source
    if (QueueNext() == false && _error->PendingError() == false)
-      _error->Error("I wasn't able to locate file for the %s package. "
-		    "This might mean you need to manually fix this package.",
+      _error->Error(_("I wasn't able to locate file for the %s package. "
+		    "This might mean you need to manually fix this package."),
 		    Version.ParentPkg().Name());
 }
 									/*}}}*/
@@ -378,7 +390,7 @@ pkgAcqArchive::pkgAcqArchive(pkgAcquire *Owner,pkgSourceList *Sources,
    the archive is already available in the cache and stashs the MD5 for
    checking later. */
 bool pkgAcqArchive::QueueNext()
-{
+{   
    for (; Vf.end() == false; Vf++)
    {
       // Ignore not source sources
@@ -386,26 +398,21 @@ bool pkgAcqArchive::QueueNext()
 	 continue;
 
       // Try to cross match against the source list
-      string PkgFile = flNotDir(Vf.File().FileName());
-      pkgSourceList::const_iterator Location;
-      for (Location = Sources->begin(); Location != Sources->end(); Location++)
-	 if (PkgFile == URItoFileName(Location->PackagesURI()))
-	    break;
-
-      if (Location == Sources->end())
-	 continue;
+      pkgIndexFile *Index;
+      if (Sources->FindIndex(Vf.File(),Index) == false)
+	    continue;
       
       // Grab the text package record
       pkgRecords::Parser &Parse = Recs->Lookup(Vf);
       if (_error->PendingError() == true)
 	 return false;
       
-      PkgFile = Parse.FileName();
+      string PkgFile = Parse.FileName();
       MD5 = Parse.MD5Hash();
       if (PkgFile.empty() == true)
-	 return _error->Error("The package index files are corrupted. No Filename: "
-			      "field for package %s."
-			      ,Version.ParentPkg().Name());
+	 return _error->Error(_("The package index files are corrupted. No Filename: "
+			      "field for package %s."),
+			      Version.ParentPkg().Name());
 
       // See if we already have the file. (Legacy filenames)
       FileSize = Version->Size;
@@ -460,8 +467,9 @@ bool pkgAcqArchive::QueueNext()
       }
       
       // Create the item
-      Desc.URI = Location->ArchiveURI(PkgFile);
-      Desc.Description = Location->ArchiveInfo(Version);
+      Local = false;
+      Desc.URI = Index->ArchiveURI(PkgFile);
+      Desc.Description = Index->ArchiveInfo(Version);
       Desc.Owner = this;
       Desc.ShortDesc = Version.ParentPkg().Name();
       QueueURI(Desc);
@@ -484,7 +492,7 @@ void pkgAcqArchive::Done(string Message,unsigned long Size,string Md5Hash,
    if (Size != Version->Size)
    {
       Status = StatError;
-      ErrorText = "Size mismatch";
+      ErrorText = _("Size mismatch");
       return;
    }
    
@@ -494,7 +502,7 @@ void pkgAcqArchive::Done(string Message,unsigned long Size,string Md5Hash,
       if (Md5Hash != MD5)
       {
 	 Status = StatError;
-	 ErrorText = "MD5Sum mismatch";
+	 ErrorText = _("MD5Sum mismatch");
 	 Rename(DestFile,DestFile + ".FAILED");
 	 return;
       }
@@ -534,6 +542,20 @@ void pkgAcqArchive::Done(string Message,unsigned long Size,string Md5Hash,
 void pkgAcqArchive::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
 {
    ErrorText = LookupTag(Message,"Message");
+   
+   /* We don't really want to retry on failed media swaps, this prevents 
+      that. An interesting observation is that permanent failures are not
+      recorded. */
+   if (Cnf->Removable == true && 
+       StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
+   {
+      // Vf = Version.FileList();
+      while (Vf.end() == false) Vf++;
+      StoreFilename = string();
+      Item::Failed(Message,Cnf);
+      return;
+   }
+   
    if (QueueNext() == false)
    {
       // This is the retry counter

+ 11 - 9
apt-pkg/acquire-item.h

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: acquire-item.h,v 1.24 2000/01/27 04:15:09 jgg Exp $
+// $Id: acquire-item.h,v 1.25 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
 
    Acquire Item - Item to acquire
@@ -21,7 +21,7 @@
 #define PKGLIB_ACQUIRE_ITEM_H
 
 #include <apt-pkg/acquire.h>
-#include <apt-pkg/sourcelist.h>
+#include <apt-pkg/indexfile.h>
 #include <apt-pkg/pkgrecords.h>
 
 #ifdef __GNUG__
@@ -49,7 +49,7 @@ class pkgAcquire::Item
    string ErrorText;
    unsigned long FileSize;
    unsigned long PartialSize;   
-   char *Mode;
+   const char *Mode;
    unsigned long ID;
    bool Complete;
    bool Local;
@@ -82,10 +82,10 @@ class pkgAcqIndex : public pkgAcquire::Item
 {
    protected:
    
-   const pkgSourceList::Item *Location;
    bool Decompression;
    bool Erase;
    pkgAcquire::ItemDesc Desc;
+   string RealURI;
    
    public:
    
@@ -93,9 +93,10 @@ class pkgAcqIndex : public pkgAcquire::Item
    virtual void Done(string Message,unsigned long Size,string Md5Hash,
 		     pkgAcquire::MethodConfig *Cnf);
    virtual string Custom600Headers();
-   virtual string DescURI() {return Location->PackagesURI();};
+   virtual string DescURI() {return RealURI;};
 
-   pkgAcqIndex(pkgAcquire *Owner,const pkgSourceList::Item *Location);
+   pkgAcqIndex(pkgAcquire *Owner,string URI,string URIDesc,
+	       string ShortDesct);
 };
 
 // Item class for index files
@@ -103,8 +104,8 @@ class pkgAcqIndexRel : public pkgAcquire::Item
 {
    protected:
    
-   const pkgSourceList::Item *Location;
    pkgAcquire::ItemDesc Desc;
+   string RealURI;
    
    public:
    
@@ -113,9 +114,10 @@ class pkgAcqIndexRel : public pkgAcquire::Item
    virtual void Done(string Message,unsigned long Size,string Md5Hash,
 		     pkgAcquire::MethodConfig *Cnf);   
    virtual string Custom600Headers();
-   virtual string DescURI() {return Location->ReleaseURI();};
+   virtual string DescURI() {return RealURI;};
    
-   pkgAcqIndexRel(pkgAcquire *Owner,const pkgSourceList::Item *Location);
+   pkgAcqIndexRel(pkgAcquire *Owner,string URI,string URIDesc,
+	       string ShortDesct);
 };
 
 // Item class for archive files

+ 6 - 4
apt-pkg/acquire-method.cc

@@ -1,12 +1,12 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: acquire-method.cc,v 1.24 2000/01/17 07:11:49 jgg Exp $
+// $Id: acquire-method.cc,v 1.25 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
 
    Acquire Method
 
    This is a skeleton class that implements most of the functionality
-   of a method and some usefull functions to make method implementation
+   of a method and some useful functions to make method implementation
    simpler. The methods all derive this and specialize it. The most
    complex implementation is the http method which needs to provide
    pipelining, it runs the message engine at the same time it is 
@@ -97,7 +97,8 @@ void pkgAcqMethod::Fail(string Err,bool Transient)
    if (Queue != 0)
    {
       snprintf(S,sizeof(S)-50,"400 URI Failure\nURI: %s\n"
-	       "Message: %s\n",Queue->Uri.c_str(),Err.c_str());
+	       "Message: %s %s\n",Queue->Uri.c_str(),Err.c_str(),
+	       FailExtra.c_str());
 
       // Dequeue
       FetchItem *Tmp = Queue;
@@ -108,7 +109,8 @@ void pkgAcqMethod::Fail(string Err,bool Transient)
    }
    else
       snprintf(S,sizeof(S)-50,"400 URI Failure\nURI: <UNKNOWN>\n"
-	       "Message: %s\n",Err.c_str());
+	       "Message: %s %s\n",Err.c_str(),
+	       FailExtra.c_str());
       
    // Set the transient flag 
    if (Transient == true)

+ 4 - 2
apt-pkg/acquire-method.h

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: acquire-method.h,v 1.13 2000/01/17 07:11:49 jgg Exp $
+// $Id: acquire-method.h,v 1.14 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
 
    Acquire Method - Method helper class + functions
@@ -49,7 +49,8 @@ class pkgAcqMethod
    vector<string> Messages;
    FetchItem *Queue;
    FetchItem *QueueBack;
-      
+   string FailExtra;
+   
    // Handlers for messages
    virtual bool Configuration(string Message);
    virtual bool Fetch(FetchItem * /*Item*/) {return true;};
@@ -74,6 +75,7 @@ class pkgAcqMethod
    void Status(const char *Format,...);
    
    int Run(bool Single = false);
+   inline void SetFailExtraMsg(string Msg) {FailExtra = Msg;};
    
    pkgAcqMethod(const char *Ver,unsigned long Flags = 0);
    virtual ~pkgAcqMethod() {};

+ 9 - 7
apt-pkg/acquire-worker.cc

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: acquire-worker.cc,v 1.31 2000/05/10 05:56:46 jgg Exp $
+// $Id: acquire-worker.cc,v 1.32 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
 
    Acquire Worker 
@@ -22,6 +22,8 @@
 #include <apt-pkg/fileutl.h>
 #include <apt-pkg/strutl.h>
 
+#include <apti18n.h>
+    
 #include <sys/stat.h>
 #include <unistd.h>
 #include <fcntl.h>
@@ -102,7 +104,7 @@ bool pkgAcquire::Worker::Start()
    // Get the method path
    string Method = _config->FindDir("Dir::Bin::Methods") + Access;
    if (FileExists(Method) == false)
-      return _error->Error("The method driver %s could not be found.",Method.c_str());
+      return _error->Error(_("The method driver %s could not be found."),Method.c_str());
 
    if (Debug == true)
       clog << "Starting method '" << Method << '\'' << endl;
@@ -154,7 +156,7 @@ bool pkgAcquire::Worker::Start()
    // Read the configuration data
    if (WaitFd(InFd) == false ||
        ReadMessages() == false)
-      return _error->Error("Method %s did not start correctly",Method.c_str());
+      return _error->Error(_("Method %s did not start correctly"),Method.c_str());
 
    RunMessages();
    if (OwnerQ != 0)
@@ -260,9 +262,9 @@ bool pkgAcquire::Worker::RunMessages()
 	       Log->Pulse(Owner->GetOwner());
 	    
 	    OwnerQ->ItemDone(Itm);
-	    if (TotalSize != 0 && 
+	    if (TotalSize != 0 &&
 		(unsigned)atoi(LookupTag(Message,"Size","0").c_str()) != TotalSize)
-	       _error->Warning("Bizzar Error - File size is not what the server reported %s %u",
+	       _error->Warning("Bizarre Error - File size is not what the server reported %s %lu",
 			       LookupTag(Message,"Size","0").c_str(),TotalSize);
 
 	    Owner->Done(Message,atoi(LookupTag(Message,"Size","0").c_str()),
@@ -313,7 +315,7 @@ bool pkgAcquire::Worker::RunMessages()
 	 
 	 // 401 General Failure
 	 case 401:
-	 _error->Error("Method %s General failure: %s",LookupTag(Message,"Message").c_str());
+	 _error->Error("Method %s General failure: %s",Access.c_str(),LookupTag(Message,"Message").c_str());
 	 break;
 	 
 	 // 403 Media Change
@@ -405,7 +407,7 @@ bool pkgAcquire::Worker::SendConfiguration()
    {
       if (Top->Value.empty() == false)
       {
-	 string Line = "Config-Item: " + Top->FullTag() + "=";
+	 string Line = "Config-Item: " + QuoteString(Top->FullTag(),"=\"\n") + "=";
 	 Line += QuoteString(Top->Value,"\n") + '\n';
 	 Message += Line;
       }

+ 3 - 3
apt-pkg/acquire-worker.h

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: acquire-worker.h,v 1.11 1999/10/18 00:37:35 jgg Exp $
+// $Id: acquire-worker.h,v 1.12 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
 
    Acquire Worker - Worker process manager
@@ -21,10 +21,10 @@
 // Interfacing to the method process
 class pkgAcquire::Worker
 {
-   friend pkgAcquire;
+   friend class pkgAcquire;
    
    protected:
-   friend Queue;
+   friend class Queue;
 
    /* Linked list starting at a Queue and a linked list starting
       at Acquire */

+ 14 - 12
apt-pkg/acquire.cc

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: acquire.cc,v 1.46 2000/01/27 04:15:09 jgg Exp $
+// $Id: acquire.cc,v 1.47 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
 
    Acquire - File Acquiration
@@ -23,6 +23,8 @@
 #include <apt-pkg/error.h>
 #include <apt-pkg/strutl.h>
 
+#include <apti18n.h>
+    
 #include <dirent.h>
 #include <sys/time.h>
 #include <errno.h>
@@ -52,11 +54,11 @@ pkgAcquire::pkgAcquire(pkgAcquireStatus *Log) : Log(Log)
    struct stat St;
    if (stat((_config->FindDir("Dir::State::lists") + "partial/").c_str(),&St) != 0 ||
        S_ISDIR(St.st_mode) == 0)
-      _error->Error("Lists directory %spartial is missing.",
+      _error->Error(_("Lists directory %spartial is missing."),
 		    _config->FindDir("Dir::State::lists").c_str());
    if (stat((_config->FindDir("Dir::Cache::Archives") + "partial/").c_str(),&St) != 0 ||
        S_ISDIR(St.st_mode) == 0)
-      _error->Error("Archive directory %spartial is missing.",
+      _error->Error(_("Archive directory %spartial is missing."),
 		    _config->FindDir("Dir::Cache::Archives").c_str());
 }
 									/*}}}*/
@@ -398,13 +400,13 @@ bool pkgAcquire::Clean(string Dir)
 {
    DIR *D = opendir(Dir.c_str());   
    if (D == 0)
-      return _error->Errno("opendir","Unable to read %s",Dir.c_str());
+      return _error->Errno("opendir",_("Unable to read %s"),Dir.c_str());
    
    string StartDir = SafeGetCWD();
    if (chdir(Dir.c_str()) != 0)
    {
       closedir(D);
-      return _error->Errno("chdir","Unable to change to ",Dir.c_str());
+      return _error->Errno("chdir",_("Unable to change to %s"),Dir.c_str());
    }
    
    for (struct dirent *Dir = readdir(D); Dir != 0; Dir = readdir(D))
@@ -435,9 +437,9 @@ bool pkgAcquire::Clean(string Dir)
 // Acquire::TotalNeeded - Number of bytes to fetch			/*{{{*/
 // ---------------------------------------------------------------------
 /* This is the total number of bytes needed */
-unsigned long pkgAcquire::TotalNeeded()
+double pkgAcquire::TotalNeeded()
 {
-   unsigned long Total = 0;
+   double Total = 0;
    for (pkgAcquire::Item **I = ItemsBegin(); I != ItemsEnd(); I++)
       Total += (*I)->FileSize;
    return Total;
@@ -446,9 +448,9 @@ unsigned long pkgAcquire::TotalNeeded()
 // Acquire::FetchNeeded - Number of bytes needed to get			/*{{{*/
 // ---------------------------------------------------------------------
 /* This is the number of bytes that is not local */
-unsigned long pkgAcquire::FetchNeeded()
+double pkgAcquire::FetchNeeded()
 {
-   unsigned long Total = 0;
+   double Total = 0;
    for (pkgAcquire::Item **I = ItemsBegin(); I != ItemsEnd(); I++)
       if ((*I)->Local == false)
 	 Total += (*I)->FileSize;
@@ -458,9 +460,9 @@ unsigned long pkgAcquire::FetchNeeded()
 // Acquire::PartialPresent - Number of partial bytes we already have	/*{{{*/
 // ---------------------------------------------------------------------
 /* This is the number of bytes that is not local */
-unsigned long pkgAcquire::PartialPresent()
+double pkgAcquire::PartialPresent()
 {
-   unsigned long Total = 0;
+  double Total = 0;
    for (pkgAcquire::Item **I = ItemsBegin(); I != ItemsEnd(); I++)
       if ((*I)->Local == false)
 	 Total += (*I)->PartialSize;
@@ -736,7 +738,7 @@ bool pkgAcquireStatus::Pulse(pkgAcquire *Owner)
       // Totally ignore local items
       if ((*I)->Local == true)
 	 continue;
-      
+
       TotalBytes += (*I)->FileSize;
       if ((*I)->Complete == true)
 	 CurrentBytes += (*I)->FileSize;

+ 13 - 12
apt-pkg/acquire.h

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: acquire.h,v 1.27 2000/01/27 04:15:09 jgg Exp $
+// $Id: acquire.h,v 1.28 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
 
    Acquire - File Acquiration
@@ -52,8 +52,8 @@ class pkgAcquire
    class Worker;
    struct MethodConfig;
    struct ItemDesc;
-   friend Item;
-   friend Queue;
+   friend class Item;
+   friend class Queue;
    
    protected:
    
@@ -112,9 +112,9 @@ class pkgAcquire
    bool Clean(string Dir);
 
    // Returns the size of the total download set
-   unsigned long TotalNeeded();
-   unsigned long FetchNeeded();
-   unsigned long PartialPresent();
+   double TotalNeeded();
+   double FetchNeeded();
+   double PartialPresent();
    
    pkgAcquire(pkgAcquireStatus *Log = 0);
    virtual ~pkgAcquire();
@@ -132,8 +132,9 @@ struct pkgAcquire::ItemDesc
 // List of possible items queued for download.
 class pkgAcquire::Queue
 {
-   friend pkgAcquire;
-   friend pkgAcquire::UriIterator;
+   friend class pkgAcquire;
+   friend class pkgAcquire::UriIterator;
+   friend class pkgAcquire::Worker;
    Queue *Next;
    
    protected:
@@ -241,11 +242,11 @@ class pkgAcquireStatus
    
    struct timeval Time;
    struct timeval StartTime;
-   unsigned long LastBytes;
+   double LastBytes;
    double CurrentCPS;
-   unsigned long CurrentBytes;
-   unsigned long TotalBytes;
-   unsigned long FetchedBytes;
+   double CurrentBytes;
+   double TotalBytes;
+   double FetchedBytes;
    unsigned long ElapsedTime;
    unsigned long TotalItems;
    unsigned long CurrentItems;

+ 156 - 67
apt-pkg/algorithms.cc

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: algorithms.cc,v 1.31 2000/10/03 23:59:05 jgg Exp $
+// $Id: algorithms.cc,v 1.32 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
 
    Algorithms - A set of misc algorithms
@@ -20,6 +20,10 @@
 #include <apt-pkg/algorithms.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/configuration.h>
+#include <apt-pkg/sptr.h>
+    
+#include <apti18n.h>
+    
 #include <iostream.h>
 									/*}}}*/
 
@@ -27,19 +31,41 @@ pkgProblemResolver *pkgProblemResolver::This = 0;
 
 // Simulate::Simulate - Constructor					/*{{{*/
 // ---------------------------------------------------------------------
-/* */
-pkgSimulate::pkgSimulate(pkgDepCache &Cache) : pkgPackageManager(Cache), 
-                            Sim(Cache.GetMap())
+/* The legacy translations here of input Pkg iterators is obsolete, 
+   this is not necessary since the pkgCaches are fully shared now. */
+pkgSimulate::pkgSimulate(pkgDepCache *Cache) : pkgPackageManager(Cache),
+		            iPolicy(Cache),
+                            Sim(&Cache->GetCache(),&iPolicy)
 {
-   Flags = new unsigned char[Cache.HeaderP->PackageCount];
-   memset(Flags,0,sizeof(*Flags)*Cache.HeaderP->PackageCount);
+   Sim.Init(0);
+   Flags = new unsigned char[Cache->Head().PackageCount];
+   memset(Flags,0,sizeof(*Flags)*Cache->Head().PackageCount);
 
    // Fake a filename so as not to activate the media swapping
    string Jnk = "SIMULATE";
-   for (unsigned int I = 0; I != Cache.Head().PackageCount; I++)
+   for (unsigned int I = 0; I != Cache->Head().PackageCount; I++)
       FileNames[I] = Jnk;
 }
 									/*}}}*/
+// Simulate::Describe - Describe a package				/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+void pkgSimulate::Describe(PkgIterator Pkg,ostream &out,bool Now)
+{
+   VerIterator Ver(Sim);
+   if (Now == true)
+      Ver = Pkg.CurrentVer();
+   else
+      Ver = Sim[Pkg].CandidateVerIter(Sim);
+
+   out << Pkg.Name();
+   
+   if (Ver.end() == true)
+      return;
+   
+   out << " (" << Ver.VerStr() << ' ' << Ver.RelStr() << ')';
+}
+									/*}}}*/
 // Simulate::Install - Simulate unpacking of a package			/*{{{*/
 // ---------------------------------------------------------------------
 /* */
@@ -49,7 +75,8 @@ bool pkgSimulate::Install(PkgIterator iPkg,string /*File*/)
    PkgIterator Pkg = Sim.FindPkg(iPkg.Name());
    Flags[Pkg->ID] = 1;
    
-   cout << "Inst " << Pkg.Name();
+   cout << "Inst ";
+   Describe(Pkg,cout,false);
    Sim.MarkInstall(Pkg,false);
    
    // Look for broken conflicts+predepends.
@@ -58,16 +85,23 @@ bool pkgSimulate::Install(PkgIterator iPkg,string /*File*/)
       if (Sim[I].InstallVer == 0)
 	 continue;
       
-      for (DepIterator D = Sim[I].InstVerIter(Sim).DependsList(); D.end() == false; D++)
-	 if (D->Type == pkgCache::Dep::Conflicts || D->Type == pkgCache::Dep::PreDepends)
+      for (DepIterator D = Sim[I].InstVerIter(Sim).DependsList(); D.end() == false;)
+      {
+	 DepIterator Start;
+	 DepIterator End;
+	 D.GlobOr(Start,End);
+	 if (Start->Type == pkgCache::Dep::Conflicts ||
+	     Start->Type == pkgCache::Dep::Obsoletes ||
+	     End->Type == pkgCache::Dep::PreDepends)
          {
-	    if ((Sim[D] & pkgDepCache::DepInstall) == 0)
+	    if ((Sim[End] & pkgDepCache::DepGInstall) == 0)
 	    {
-	       cout << " [" << I.Name() << " on " << D.TargetPkg().Name() << ']';
-	       if (D->Type == pkgCache::Dep::Conflicts)
+	       cout << " [" << I.Name() << " on " << Start.TargetPkg().Name() << ']';
+	       if (Start->Type == pkgCache::Dep::Conflicts)
 		  _error->Error("Fatal, conflicts violated %s",I.Name());
 	    }	    
-	 }      
+	 }
+      }      
    }
 
    if (Sim.BrokenCount() != 0)
@@ -102,7 +136,9 @@ bool pkgSimulate::Configure(PkgIterator iPkg)
 	     (Sim[D] & pkgDepCache::DepInstall) != 0)
 	    continue;
 	 
-	 if (D->Type == pkgCache::Dep::Conflicts)
+	 if (D->Type == pkgCache::Dep::Obsoletes)
+	    cout << " Obsoletes:" << D.TargetPkg().Name();
+	 else if (D->Type == pkgCache::Dep::Conflicts)
 	    cout << " Conflicts:" << D.TargetPkg().Name();
 	 else
 	    cout << " Depends:" << D.TargetPkg().Name();
@@ -112,7 +148,10 @@ bool pkgSimulate::Configure(PkgIterator iPkg)
       _error->Error("Conf Broken %s",Pkg.Name());
    }   
    else
-      cout << "Conf " <<  Pkg.Name();
+   {
+      cout << "Conf "; 
+      Describe(Pkg,cout,false);
+   }
 
    if (Sim.BrokenCount() != 0)
       ShortBreaks();
@@ -133,9 +172,10 @@ bool pkgSimulate::Remove(PkgIterator iPkg,bool Purge)
    Flags[Pkg->ID] = 3;
    Sim.MarkDelete(Pkg);
    if (Purge == true)
-      cout << "Purg " << Pkg.Name();
+      cout << "Purg ";
    else
-      cout << "Remv " << Pkg.Name();
+      cout << "Remv ";
+   Describe(Pkg,cout,false);
 
    if (Sim.BrokenCount() != 0)
       ShortBreaks();
@@ -185,8 +225,8 @@ bool pkgApplyStatus(pkgDepCache &Cache)
 	    if (Cache[I].CandidateVerIter(Cache).Downloadable() == true)
 	       Cache.MarkInstall(I);
 	    else
-	       return _error->Error("The package %s needs to be reinstalled, "
-				    "but I can't find an archive for it.",I.Name());
+	       return _error->Error(_("The package %s needs to be reinstalled, "
+				    "but I can't find an archive for it."),I.Name());
 	 }
 	 
 	 continue;
@@ -249,7 +289,7 @@ bool pkgFixBroken(pkgDepCache &Cache)
       Cache.MarkInstall(I,true);      
    }
    
-   pkgProblemResolver Fix(Cache);
+   pkgProblemResolver Fix(&Cache);
    return Fix.Resolve(true);
 }
 									/*}}}*/
@@ -281,7 +321,7 @@ bool pkgDistUpgrade(pkgDepCache &Cache)
       if (I->CurrentVer != 0)
 	 Cache.MarkInstall(I,false);
 
-   pkgProblemResolver Fix(Cache);
+   pkgProblemResolver Fix(&Cache);
 
    // Hold back held packages.
    if (_config->FindB("APT::Ignore-Hold",false) == false)
@@ -306,7 +346,7 @@ bool pkgDistUpgrade(pkgDepCache &Cache)
    to install packages not marked for install */
 bool pkgAllUpgrade(pkgDepCache &Cache)
 {
-   pkgProblemResolver Fix(Cache);
+   pkgProblemResolver Fix(&Cache);
 
    if (Cache.BrokenCount() != 0)
       return false;
@@ -317,7 +357,7 @@ bool pkgAllUpgrade(pkgDepCache &Cache)
       if (Cache[I].Install() == true)
 	 Fix.Protect(I);
 	  
-      if (_config->FindB("APT::Ingore-Hold",false) == false)
+      if (_config->FindB("APT::Ignore-Hold",false) == false)
 	 if (I->SelectedState == pkgCache::State::Hold)
 	    continue;
       
@@ -375,10 +415,10 @@ bool pkgMinimizeUpgrade(pkgDepCache &Cache)
 // ProblemResolver::pkgProblemResolver - Constructor			/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-pkgProblemResolver::pkgProblemResolver(pkgDepCache &Cache) : Cache(Cache)
+pkgProblemResolver::pkgProblemResolver(pkgDepCache *pCache) : Cache(*pCache)
 {
    // Allocate memory
-   unsigned long Size = Cache.HeaderP->PackageCount;
+   unsigned long Size = Cache.Head().PackageCount;
    Scores = new signed short[Size];
    Flags = new unsigned char[Size];
    memset(Flags,0,sizeof(*Flags)*Size);
@@ -387,6 +427,15 @@ pkgProblemResolver::pkgProblemResolver(pkgDepCache &Cache) : Cache(Cache)
    Debug = _config->FindB("Debug::pkgProblemResolver",false);
 }
 									/*}}}*/
+// ProblemResolver::~pkgProblemResolver - Destructor			/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+pkgProblemResolver::~pkgProblemResolver()
+{
+   delete [] Scores;
+   delete [] Flags;
+}
+									/*}}}*/
 // ProblemResolver::ScoreSort - Sort the list by score			/*{{{*/
 // ---------------------------------------------------------------------
 /* */
@@ -406,7 +455,7 @@ int pkgProblemResolver::ScoreSort(const void *a,const void *b)
 /* */
 void pkgProblemResolver::MakeScores()
 {
-   unsigned long Size = Cache.HeaderP->PackageCount;
+   unsigned long Size = Cache.Head().PackageCount;
    memset(Scores,0,sizeof(*Scores)*Size);
 
    // Generate the base scores for a package based on its properties
@@ -450,7 +499,7 @@ void pkgProblemResolver::MakeScores()
    }   
    
    // Copy the scores to advoid additive looping
-   signed short *OldScores = new signed short[Size];
+   SPtrArray<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 
@@ -493,9 +542,7 @@ void pkgProblemResolver::MakeScores()
 	 Scores[I->ID] += 10000;
       if ((I->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
 	 Scores[I->ID] += 5000;
-   }
-   
-   delete [] OldScores;
+   }   
 }
 									/*}}}*/
 // ProblemResolver::DoUpgrade - Attempt to upgrade this package		/*{{{*/
@@ -573,8 +620,9 @@ bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg)
 	    {
 	       /* We let the algorithm deal with conflicts on its next iteration,
 		it is much smarter than us */
-	       if (Start->Type == pkgCache::Dep::Conflicts)
-		  break;
+	       if (Start->Type == pkgCache::Dep::Conflicts || 
+		   Start->Type == pkgCache::Dep::Obsoletes)
+		   break;
 	       
 	       if (Debug == true)
 		  clog << "    Reinst Failed early because of " << Start.TargetPkg().Name() << endl;
@@ -621,7 +669,7 @@ bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg)
    upgrade packages to advoid problems. */
 bool pkgProblemResolver::Resolve(bool BrokenFix)
 {
-   unsigned long Size = Cache.HeaderP->PackageCount;
+   unsigned long Size = Cache.Head().PackageCount;
 
    // Record which packages are marked for install
    bool Again = false;
@@ -657,7 +705,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
       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];
+   SPtrArray<pkgCache::Package *> PList = new pkgCache::Package *[Size];
    pkgCache::Package **PEnd = PList;
    for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
       *PEnd++ = I;
@@ -728,19 +776,12 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
 	 bool InOr = false;
 	 pkgCache::DepIterator Start;
 	 pkgCache::DepIterator End;
-	 PackageKill *OldEnd;
+	 PackageKill *OldEnd = LEnd;
 	 
 	 enum {OrRemove,OrKeep} OrOp = OrRemove;
 	 for (pkgCache::DepIterator D = Cache[I].InstVerIter(Cache).DependsList();
 	      D.end() == false || InOr == true;)
 	 {
-	    // We only worry about critical deps.
-	    if (D.IsCritical() != true)
-	    {
-	       D++;
-	       continue;
-	    }
-	    
 	    // Compute a single dependency element (glob or)
 	    if (Start == End)
 	    {
@@ -761,13 +802,22 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
 		     if (Debug == true)
 			clog << "  Or group keep for " << I.Name() << endl;
 		     Cache.MarkKeep(I);
-		  }		  
+		  }
 	       }
 	       
+	       /* We do an extra loop (as above) to finalize the or group
+		  processing */
+	       InOr = false;
 	       OrOp = OrRemove;
 	       D.GlobOr(Start,End);
+	       if (Start.end() == true)
+		  break;
+	       
+	       // We only worry about critical deps.
+	       if (End.IsCritical() != true)
+		  continue;
+	       
 	       InOr = Start != End;
-	       cout << Start.TargetPkg().Name() << ',' << End.TargetPkg().Name() << ',' << InOr << endl;
 	       OldEnd = LEnd;
 	    }	    
 	    else
@@ -783,9 +833,10 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
 	    /* Look across the version list. If there are no possible
 	       targets then we keep the package and bail. This is necessary
 	       if a package has a dep on another package that cant be found */
-	    pkgCache::Version **VList = Start.AllTargets();
+	    SPtrArray<pkgCache::Version *> VList = Start.AllTargets();
 	    if (*VList == 0 && (Flags[I->ID] & Protected) != Protected &&
 		Start->Type != pkgCache::Dep::Conflicts &&
+		Start->Type != pkgCache::Dep::Obsoletes &&
 		Cache[I].NowBroken() == false)
 	    {	       
 	       if (InOr == true)
@@ -811,14 +862,16 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
 		  " as a solution to " << I.Name() << ' ' << (int)Scores[I->ID] << endl;
 	       if (Scores[I->ID] <= Scores[Pkg->ID] ||
 		   ((Cache[Start] & pkgDepCache::DepNow) == 0 &&
-		    End->Type != pkgCache::Dep::Conflicts))
+		    End->Type != pkgCache::Dep::Conflicts &&
+		    End->Type != pkgCache::Dep::Obsoletes))
 	       {
 		  // Try a little harder to fix protected packages..
 		  if ((Flags[I->ID] & Protected) == Protected)
 		  {
 		     if (DoUpgrade(Pkg) == true)
 		     {
-			Scores[Pkg->ID] = Scores[I->ID];
+			if (Scores[Pkg->ID] > Scores[I->ID])
+			   Scores[Pkg->ID] = Scores[I->ID];
 			break;
 		     }
 		     
@@ -853,7 +906,10 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
 			      clog << "  Removing " << I.Name() << " rather than change " << Start.TargetPkg().Name() << endl;
 			   Cache.MarkDelete(I);
 			   if (Counter > 1)
-			      Scores[I->ID] = Scores[Pkg->ID];
+			   {
+			      if (Scores[Pkg->ID] > Scores[I->ID])
+				 Scores[I->ID] = Scores[Pkg->ID];
+			   }			   
 			}			
 		     }
 		  }
@@ -874,13 +930,16 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
 		  LEnd->Dep = End;
 		  LEnd++;
 		  
-		  if (Start->Type != pkgCache::Dep::Conflicts)
+		  if (Start->Type != pkgCache::Dep::Conflicts &&
+		      Start->Type != pkgCache::Dep::Obsoletes)
 		     break;
 	       }
 	    }
 
 	    // Hm, nothing can possibly satisify this dep. Nuke it.
-	    if (VList[0] == 0 && Start->Type != pkgCache::Dep::Conflicts &&
+	    if (VList[0] == 0 && 
+		Start->Type != pkgCache::Dep::Conflicts &&
+		Start->Type != pkgCache::Dep::Obsoletes &&
 		(Flags[I->ID] & Protected) != Protected)
 	    {
 	       bool Installed = Cache[I].Install();
@@ -910,8 +969,6 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
 	       Done = true;
 	    }
 	    
-	    delete [] VList;
-	    
 	    // Try some more
 	    if (InOr == true)
 	       continue;
@@ -928,7 +985,8 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
 	       Change = true;
 	       if ((Cache[J->Dep] & pkgDepCache::DepGNow) == 0)
 	       {
-		  if (J->Dep->Type == pkgCache::Dep::Conflicts)
+		  if (J->Dep->Type == pkgCache::Dep::Conflicts || 
+		      J->Dep->Type == pkgCache::Dep::Obsoletes)
 		  {
 		     if (Debug == true)
 			clog << "  Fixing " << I.Name() << " via remove of " << J->Pkg.Name() << endl;
@@ -941,9 +999,12 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
 		     clog << "  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 (Scores[I->ID] > Scores[J->Pkg->ID])		  
+		     Scores[J->Pkg->ID] = Scores[I->ID];
+	       }	       
 	    }      
 	 }
       }      
@@ -951,10 +1012,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
 
    if (Debug == true)
       clog << "Done" << endl;
-   
-   delete [] Scores;
-   delete [] PList;
-   
+      
    if (Cache.BrokenCount() != 0)
    {
       // See if this is the result of a hold
@@ -964,9 +1022,9 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
 	 if (Cache[I].InstBroken() == false)
 	    continue;
 	 if ((Flags[I->ID] & Protected) != Protected)
-	    return _error->Error("Error, pkgProblemResolver::Resolve generated breaks, this may be caused by held packages.");
+	    return _error->Error(_("Error, pkgProblemResolver::Resolve generated breaks, this may be caused by held packages."));
       }
-      return _error->Error("Unable to correct problems, you have held broken packages.");
+      return _error->Error(_("Unable to correct problems, you have held broken packages."));
    }
    
    return true;
@@ -979,7 +1037,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
    system was non-broken previously. */
 bool pkgProblemResolver::ResolveByKeep()
 {
-   unsigned long Size = Cache.HeaderP->PackageCount;
+   unsigned long Size = Cache.Head().PackageCount;
 
    if (Debug == true)      
       clog << "Entering ResolveByKeep" << endl;
@@ -1007,7 +1065,7 @@ bool pkgProblemResolver::ResolveByKeep()
 	 continue;
 
       /* Keep the package. If this works then great, otherwise we have
-       	 to be significantly more agressive and manipulate its dependencies */      
+       	 to be significantly more agressive and manipulate its dependencies */
       if ((Flags[I->ID] & Protected) == 0)
       {
 	 if (Debug == true)
@@ -1015,7 +1073,7 @@ bool pkgProblemResolver::ResolveByKeep()
 	 Cache.MarkKeep(I);
 	 if (Cache[I].InstBroken() == false)
 	 {
-	    K = PList;
+	    K = PList - 1;
 	    continue;
 	 }
       }
@@ -1056,7 +1114,7 @@ bool pkgProblemResolver::ResolveByKeep()
 	    clog << "Package " << I.Name() << " has broken dep on " << End.TargetPkg().Name() << endl;
 	 
 	 // Look at all the possible provides on this package
-	 pkgCache::Version **VList = End.AllTargets();
+	 SPtrArray<pkgCache::Version *> VList = End.AllTargets();
 	 for (pkgCache::Version **V = VList; *V != 0; V++)
 	 {
 	    pkgCache::VerIterator Ver(Cache,*V);
@@ -1089,7 +1147,7 @@ bool pkgProblemResolver::ResolveByKeep()
       if (K == LastStop)
 	 return _error->Error("Internal Error, pkgProblemResolver::ResolveByKeep is looping on package %s.",I.Name());
       LastStop = K;
-      K = PList;
+      K = PList - 1;
    }   
 
    return true;
@@ -1112,3 +1170,34 @@ void pkgProblemResolver::InstallProtect()
    }   
 }
 									/*}}}*/
+
+// PrioSortList - Sort a list of versions by priority			/*{{{*/
+// ---------------------------------------------------------------------
+/* This is ment to be used in conjunction with AllTargets to get a list 
+   of versions ordered by preference. */
+static pkgCache *PrioCache;
+static int PrioComp(const void *A,const void *B)
+{
+   pkgCache::VerIterator L(*PrioCache,*(pkgCache::Version **)A);
+   pkgCache::VerIterator R(*PrioCache,*(pkgCache::Version **)B);
+   
+   if ((L.ParentPkg()->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential &&
+       (L.ParentPkg()->Flags & pkgCache::Flag::Essential) != pkgCache::Flag::Essential)
+   return 1;
+   if ((L.ParentPkg()->Flags & pkgCache::Flag::Essential) != pkgCache::Flag::Essential &&
+       (L.ParentPkg()->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
+   return -1;
+   
+   if (L->Priority != R->Priority)
+      return L->Priority - R->Priority;
+   return strcmp(L.ParentPkg().Name(),R.ParentPkg().Name());
+}
+void pkgPrioSortList(pkgCache &Cache,pkgCache::Version **List)
+{
+   unsigned long Count = 0;
+   PrioCache = &Cache;
+   for (pkgCache::Version **I = List; *I != 0; I++)
+      Count++;
+   qsort(List,Count,sizeof(*List),PrioComp);
+}
+									/*}}}*/

+ 21 - 4
apt-pkg/algorithms.h

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: algorithms.h,v 1.8 1999/10/27 04:38:27 jgg Exp $
+// $Id: algorithms.h,v 1.9 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
 
    Algorithms - A set of misc algorithms
@@ -27,7 +27,6 @@
 
    ##################################################################### */
 									/*}}}*/
-// Header section: pkglib
 #ifndef PKGLIB_ALGORITHMS_H
 #define PKGLIB_ALGORITHMS_H
 
@@ -42,8 +41,22 @@ class pkgSimulate : public pkgPackageManager
 {
    protected:
 
+   class Policy : public pkgDepCache::Policy
+   {
+      pkgDepCache *Cache;
+      public:
+      
+      virtual VerIterator GetCandidateVer(PkgIterator Pkg)
+      {
+	 return (*Cache)[Pkg].CandidateVerIter(*Cache);
+      }
+      
+      Policy(pkgDepCache *Cache) : Cache(Cache) {};
+   };
+   
    unsigned char *Flags;
    
+   Policy iPolicy;
    pkgDepCache Sim;
    
    // The Actuall installation implementation
@@ -51,10 +64,11 @@ class pkgSimulate : public pkgPackageManager
    virtual bool Configure(PkgIterator Pkg);
    virtual bool Remove(PkgIterator Pkg,bool Purge);
    void ShortBreaks();
+   void Describe(PkgIterator iPkg,ostream &out,bool Now);
    
    public:
 
-   pkgSimulate(pkgDepCache &Cache);
+   pkgSimulate(pkgDepCache *Cache);
 };
 
 class pkgProblemResolver
@@ -101,7 +115,8 @@ class pkgProblemResolver
    
    void InstallProtect();   
    
-   pkgProblemResolver(pkgDepCache &Cache);
+   pkgProblemResolver(pkgDepCache *Cache);
+   ~pkgProblemResolver();
 };
 
 bool pkgDistUpgrade(pkgDepCache &Cache);
@@ -110,4 +125,6 @@ bool pkgFixBroken(pkgDepCache &Cache);
 bool pkgAllUpgrade(pkgDepCache &Cache);
 bool pkgMinimizeUpgrade(pkgDepCache &Cache);
 
+void pkgPrioSortList(pkgCache &Cache,pkgCache::Version **List);
+		     
 #endif

+ 56 - 34
apt-pkg/cachefile.cc

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: cachefile.cc,v 1.4 1999/06/24 04:06:30 jgg Exp $
+// $Id: cachefile.cc,v 1.5 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
    
    CacheFile - Simple wrapper class for opening, generating and whatnot
@@ -21,23 +21,29 @@
 #include <apt-pkg/sourcelist.h>
 #include <apt-pkg/pkgcachegen.h>
 #include <apt-pkg/configuration.h>
+#include <apt-pkg/policy.h>
+#include <apt-pkg/pkgsystem.h>
+    
+#include <apti18n.h>
 									/*}}}*/
 
 // CacheFile::CacheFile - Constructor					/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-pkgCacheFile::pkgCacheFile() : Map(0), Cache(0), Lock(0) 
+pkgCacheFile::pkgCacheFile() : Map(0), Cache(0), DCache(0), Policy(0)
 {
 }
 									/*}}}*/
-// CacheFile::~CacheFile - Destructor						/*{{{*/
+// CacheFile::~CacheFile - Destructor					/*{{{*/
 // ---------------------------------------------------------------------
 /* */
 pkgCacheFile::~pkgCacheFile()
 {
+   delete DCache;
+   delete Policy;
    delete Cache;
    delete Map;
-   delete Lock;
+   _system->UnLock(true);
 }   
 									/*}}}*/
 // CacheFile::Open - Open the cache files, creating if necessary	/*{{{*/
@@ -46,7 +52,8 @@ pkgCacheFile::~pkgCacheFile()
 bool pkgCacheFile::Open(OpProgress &Progress,bool WithLock)
 {
    if (WithLock == true)
-      Lock = new pkgDpkgLock;
+      if (_system->Lock() == false)
+	 return false;
    
    if (_error->PendingError() == true)
       return false;
@@ -54,38 +61,35 @@ bool pkgCacheFile::Open(OpProgress &Progress,bool WithLock)
    // Read the source list
    pkgSourceList List;
    if (List.ReadMainList() == false)
-      return _error->Error("The list of sources could not be read.");
+      return _error->Error(_("The list of sources could not be read."));
+
+   // Read the caches
+   bool Res = pkgMakeStatusCache(List,Progress,&Map,!WithLock);
+   Progress.Done();
+   if (Res == false)
+      return _error->Error(_("The package lists or status file could not be parsed or opened."));
+
+   /* This sux, remove it someday */
+   if (_error->empty() == false)
+      _error->Warning(_("You may want to run apt-get update to correct these missing files"));
+
+   Cache = new pkgCache(Map);
+   if (_error->PendingError() == true)
+      return false;
    
-   /* Build all of the caches, using the cache files if we are locking 
-      (ie as root) */
-   if (WithLock == true)
-   {
-      pkgMakeStatusCache(List,Progress);
-      Progress.Done();
-      if (_error->PendingError() == true)
-	 return _error->Error("The package lists or status file could not be parsed or opened.");
-      if (_error->empty() == false)
-	 _error->Warning("You may want to run apt-get update to correct these missing files");
-      
-      // Open the cache file
-      FileFd File(_config->FindFile("Dir::Cache::pkgcache"),FileFd::ReadOnly);
-      if (_error->PendingError() == true)
-	 return false;
-      
-      Map = new MMap(File,MMap::Public | MMap::ReadOnly);
-      if (_error->PendingError() == true)
-	 return false;
-   }
-   else
-   {
-      Map = pkgMakeStatusCacheMem(List,Progress);
-      Progress.Done();
-      if (Map == 0)
-	 return false;
-   }
+   // The policy engine
+   Policy = new pkgPolicy(Cache);
+   if (_error->PendingError() == true)
+      return false;
+   if (ReadPinFile(*Policy) == false)
+      return false;
    
    // Create the dependency cache
-   Cache = new pkgDepCache(*Map,Progress);
+   DCache = new pkgDepCache(Cache,Policy);
+   if (_error->PendingError() == true)
+      return false;
+   
+   DCache->Init(&Progress);
    Progress.Done();
    if (_error->PendingError() == true)
       return false;
@@ -93,3 +97,21 @@ bool pkgCacheFile::Open(OpProgress &Progress,bool WithLock)
    return true;
 }
 									/*}}}*/
+
+// CacheFile::Close - close the cache files				/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+void pkgCacheFile::Close()
+{
+   delete DCache;
+   delete Policy;
+   delete Cache;
+   delete Map;
+   _system->UnLock(true);
+
+   Map = 0;
+   DCache = 0;
+   Policy = 0;
+   Cache = 0;
+}
+									/*}}}*/

+ 18 - 13
apt-pkg/cachefile.h

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: cachefile.h,v 1.3 1999/06/27 03:18:28 jgg Exp $
+// $Id: cachefile.h,v 1.4 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
    
    CacheFile - Simple wrapper class for opening, generating and whatnot
@@ -9,6 +9,9 @@
    of caches. It can operate as root, as not root, show progress and so on,
    it transparently handles everything necessary.
    
+   This means it can rebuild caches from the source list and instantiates
+   and prepares the standard policy mechanism.
+   
    ##################################################################### */
 									/*}}}*/
 #ifndef PKGLIB_CACHEFILE_H
@@ -19,30 +22,32 @@
 #endif 
 
 #include <apt-pkg/depcache.h>
-#include <apt-pkg/dpkginit.h>
 
+class pkgPolicy;
 class pkgCacheFile
 {
    protected:
    
    MMap *Map;
-   pkgDepCache *Cache;
-   pkgDpkgLock *Lock;
+   pkgCache *Cache;
+   pkgDepCache *DCache;
    
    public:
+
+   pkgPolicy *Policy;
       
    // We look pretty much exactly like a pointer to a dep cache
-   inline operator pkgDepCache &() {return *Cache;};
-   inline operator pkgDepCache *() {return Cache;};
-   inline pkgDepCache *operator ->() {return Cache;};
-   inline pkgDepCache &operator *() {return *Cache;};
-   inline pkgDepCache::StateCache &operator [](pkgCache::PkgIterator const &I) {return (*Cache)[I];};
-   inline unsigned char &operator [](pkgCache::DepIterator const &I) {return (*Cache)[I];};
+   inline operator pkgCache &() {return *Cache;};
+   inline operator pkgCache *() {return Cache;};
+   inline operator pkgDepCache &() {return *DCache;};
+   inline operator pkgDepCache *() {return DCache;};
+   inline pkgDepCache *operator ->() {return DCache;};
+   inline pkgDepCache &operator *() {return *DCache;};
+   inline pkgDepCache::StateCache &operator [](pkgCache::PkgIterator const &I) {return (*DCache)[I];};
+   inline unsigned char &operator [](pkgCache::DepIterator const &I) {return (*DCache)[I];};
 
-   // Release the dpkg status lock
-   inline void ReleaseLock() {Lock->Close();};
-   
    bool Open(OpProgress &Progress,bool WithLock = true);
+   void Close();
    
    pkgCacheFile();
    ~pkgCacheFile();

+ 31 - 19
apt-pkg/cacheiterators.h

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: cacheiterators.h,v 1.15 1999/07/30 04:08:42 jgg Exp $
+// $Id: cacheiterators.h,v 1.16 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
    
    Cache Iterators - Iterators for navigating the cache structure
@@ -28,7 +28,6 @@
    
    ##################################################################### */
 									/*}}}*/
-// Header section: pkglib
 #ifndef PKGLIB_CACHEITERATORS_H
 #define PKGLIB_CACHEITERATORS_H
 
@@ -39,10 +38,20 @@
 // Package Iterator
 class pkgCache::PkgIterator
 {
+   friend class pkgCache;
    Package *Pkg;
    pkgCache *Owner;
    long HashIndex;
 
+   protected:
+   
+   // This constructor is the 'begin' constructor, never use it.
+   inline PkgIterator(pkgCache &Owner) : Owner(&Owner), HashIndex(-1)
+   {
+      Pkg = Owner.PkgP;
+      operator ++(0);
+   };
+   
    public:
 
    enum OkState {NeedsNothing,NeedsUnpack,NeedsConfigure};
@@ -62,10 +71,10 @@ class pkgCache::PkgIterator
    inline Package const &operator *() const {return *Pkg;};
    inline operator Package *() {return Pkg == Owner->PkgP?0:Pkg;};
    inline operator Package const *() const {return Pkg == Owner->PkgP?0:Pkg;};
+   inline pkgCache *Cache() {return Owner;};
    
    inline const char *Name() const {return Pkg->Name == 0?0:Owner->StrP + Pkg->Name;};
    inline const char *Section() const {return Pkg->Section == 0?0:Owner->StrP + Pkg->Section;};
-   inline const char *TargetDist() const {return Pkg->TargetDist == 0?0:Owner->StrP + Pkg->TargetDist;};
    inline bool Purge() const {return Pkg->CurrentState == pkgCache::State::Purge ||
 	 (Pkg->CurrentVer == 0 && Pkg->CurrentState == pkgCache::State::NotInstalled);};
    inline VerIterator VersionList() const;
@@ -77,11 +86,6 @@ class pkgCache::PkgIterator
    OkState State() const;
    
    // Constructors
-   inline PkgIterator(pkgCache &Owner) : Owner(&Owner), HashIndex(-1)
-   {
-      Pkg = Owner.PkgP;
-      operator ++(0);
-   };
    inline PkgIterator(pkgCache &Owner,Package *Trg) : Pkg(Trg), Owner(&Owner),
           HashIndex(0) 
    { 
@@ -119,7 +123,8 @@ class pkgCache::VerIterator
    inline Version const &operator *() const {return *Ver;};
    inline operator Version *() {return Ver == Owner->VerP?0:Ver;};
    inline operator Version const *() const {return Ver == Owner->VerP?0:Ver;};
-   
+   inline pkgCache *Cache() {return Owner;};
+      
    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 *Arch() const {return Ver->Arch == 0?0:Owner->StrP + Ver->Arch;};
@@ -129,8 +134,9 @@ class pkgCache::VerIterator
    inline VerFileIterator FileList() const;
    inline unsigned long Index() const {return Ver - Owner->VerP;};
    bool Downloadable() const;
-   const char *PriorityType();
-
+   inline const char *PriorityType() {return Owner->Priority(Ver->Priority);};
+   string RelStr();
+   
    bool Automatic() const;
    VerFileIterator NewestFile() const;
 
@@ -171,10 +177,11 @@ class pkgCache::DepIterator
    inline Dependency const &operator *() const {return *Dep;};
    inline operator Dependency *() {return Dep == Owner->DepP?0:Dep;};
    inline operator Dependency const *() const {return Dep == Owner->DepP?0:Dep;};
+   inline pkgCache *Cache() {return Owner;};
    
    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 SmartTargetPkg() {PkgIterator R(*Owner);SmartTargetPkg(R);return R;};
+   inline PkgIterator SmartTargetPkg() {PkgIterator R(*Owner,0);SmartTargetPkg(R);return R;};
    inline VerIterator ParentVer() {return VerIterator(*Owner,Owner->VerP + Dep->ParentVer);};
    inline PkgIterator ParentPkg() {return PkgIterator(*Owner,Owner->PkgP + Owner->VerP[Dep->ParentVer].ParentPkg);};
    inline bool Reverse() {return Type == DepRev;};
@@ -183,8 +190,8 @@ class pkgCache::DepIterator
    void GlobOr(DepIterator &Start,DepIterator &End);
    Version **AllTargets();   
    bool SmartTargetPkg(PkgIterator &Result);
-   const char *CompType();
-   const char *DepType();
+   inline const char *CompType() {return Owner->CompType(Dep->CompareOp);};
+   inline const char *DepType() {return Owner->DepType(Dep->Type);};
    
    inline DepIterator(pkgCache &Owner,Dependency *Trg,Version * = 0) :
           Dep(Trg), Type(DepVer), Owner(&Owner) 
@@ -229,6 +236,7 @@ class pkgCache::PrvIterator
    inline Provides const &operator *() const {return *Prv;};
    inline operator Provides *() {return Prv == Owner->ProvideP?0:Prv;};
    inline operator Provides const *() const {return Prv == Owner->ProvideP?0:Prv;};
+   inline pkgCache *Cache() {return Owner;};
 
    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;};
@@ -274,6 +282,7 @@ class pkgCache::PkgFileIterator
    inline PackageFile const &operator *() const {return *File;};
    inline operator PackageFile *() {return File == Owner->PkgFileP?0:File;};
    inline operator PackageFile const *() const {return File == Owner->PkgFileP?0:File;};
+   inline pkgCache *Cache() {return Owner;};
 
    inline const char *FileName() const {return File->FileName == 0?0:Owner->StrP + File->FileName;};
    inline const char *Archive() const {return File->Archive == 0?0:Owner->StrP + File->Archive;};
@@ -281,14 +290,17 @@ class pkgCache::PkgFileIterator
    inline const char *Version() const {return File->Version == 0?0:Owner->StrP + File->Version;};
    inline const char *Origin() const {return File->Origin == 0?0:Owner->StrP + File->Origin;};
    inline const char *Label() const {return File->Origin == 0?0:Owner->StrP + File->Label;};
-   inline const char *Architecture() const {return File->Origin == 0?0:Owner->StrP + File->Architecture;};
+   inline const char *Site() const {return File->Site == 0?0:Owner->StrP + File->Site;};
+   inline const char *Architecture() const {return File->Architecture == 0?0:Owner->StrP + File->Architecture;};
+   inline const char *IndexType() const {return File->IndexType == 0?0:Owner->StrP + File->IndexType;};
 
    inline unsigned long Index() const {return File - Owner->PkgFileP;};
 
    bool IsOk();
-   
+
    // Constructors
-   inline PkgFileIterator(pkgCache &Owner) : Owner(&Owner), File(Owner.PkgFileP + Owner.Head().FileList) {};
+   inline PkgFileIterator() : Owner(0), File(0) {};
+   inline PkgFileIterator(pkgCache &Owner) : Owner(&Owner), File(Owner.PkgFileP) {};
    inline PkgFileIterator(pkgCache &Owner,PackageFile *Trg) : Owner(&Owner), File(Trg) {};
 };
 
@@ -315,10 +327,12 @@ class pkgCache::VerFileIterator
    inline VerFile const &operator *() const {return *FileP;};
    inline operator VerFile *() {return FileP == Owner->VerFileP?0:FileP;};
    inline operator VerFile const *() const {return FileP == Owner->VerFileP?0:FileP;};
+   inline pkgCache *Cache() {return Owner;};
   
    inline PkgFileIterator File() const {return PkgFileIterator(*Owner,FileP->File + Owner->PkgFileP);};
    inline unsigned long Index() const {return FileP - Owner->VerFileP;};
       
+   inline VerFileIterator() : Owner(0), FileP(0) {};
    inline VerFileIterator(pkgCache &Owner,VerFile *Trg) : Owner(&Owner), FileP(Trg) {};
 };
 
@@ -327,8 +341,6 @@ inline pkgCache::VerIterator pkgCache::PkgIterator::VersionList() const
        {return VerIterator(*Owner,Owner->VerP + Pkg->VersionList);};
 inline pkgCache::VerIterator pkgCache::PkgIterator::CurrentVer() const
        {return VerIterator(*Owner,Owner->VerP + Pkg->CurrentVer);};
-inline pkgCache::VerIterator pkgCache::PkgIterator::TargetVer() const
-       {return VerIterator(*Owner,Owner->VerP + Pkg->TargetVer);};
 inline pkgCache::DepIterator pkgCache::PkgIterator::RevDependsList() const
        {return DepIterator(*Owner,Owner->DepP + Pkg->RevDepends,Pkg);};
 inline pkgCache::PrvIterator pkgCache::PkgIterator::ProvidesList() const

+ 19 - 9
apt-pkg/clean.cc

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: clean.cc,v 1.3 1999/10/03 21:09:27 jgg Exp $
+// $Id: clean.cc,v 1.4 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
 
    Clean - Clean out downloaded directories
@@ -17,6 +17,8 @@
 #include <apt-pkg/error.h>
 #include <apt-pkg/configuration.h>
 
+#include <apti18n.h>    
+
 #include <dirent.h>
 #include <sys/stat.h>
 #include <unistd.h>
@@ -29,16 +31,17 @@
 bool pkgArchiveCleaner::Go(string Dir,pkgCache &Cache)
 {
    bool CleanInstalled = _config->FindB("APT::Clean-Installed",true);
-   
-   DIR *D = opendir(Dir.c_str());   
+   string MyArch = _config->Find("APT::Architecture");
+      
+   DIR *D = opendir(Dir.c_str());
    if (D == 0)
-      return _error->Errno("opendir","Unable to read %s",Dir.c_str());
-   
+      return _error->Errno("opendir",_("Unable to read %s"),Dir.c_str());
+
    string StartDir = SafeGetCWD();
    if (chdir(Dir.c_str()) != 0)
    {
       closedir(D);
-      return _error->Errno("chdir","Unable to change to ",Dir.c_str());
+      return _error->Errno("chdir",_("Unable to change to %s"),Dir.c_str());
    }
    
    for (struct dirent *Dir = readdir(D); Dir != 0; Dir = readdir(D))
@@ -52,8 +55,12 @@ bool pkgArchiveCleaner::Go(string Dir,pkgCache &Cache)
 
       struct stat St;
       if (stat(Dir->d_name,&St) != 0)
-	 return _error->Errno("stat","Unable to stat %s.",Dir->d_name);
-
+      {
+	 chdir(StartDir.c_str());
+	 closedir(D);
+	 return _error->Errno("stat",_("Unable to stat %s."),Dir->d_name);
+      }
+      
       // Grab the package name
       const char *I = Dir->d_name;
       for (; *I != 0 && *I != '_';I++);
@@ -74,7 +81,10 @@ bool pkgArchiveCleaner::Go(string Dir,pkgCache &Cache)
       if (*I != '.')
 	 continue;
       string Arch = DeQuoteString(string(Start,I-Start));
-            
+      
+      if (Arch != "all" && Arch != MyArch)
+	 continue;
+      
       // Lookup the package
       pkgCache::PkgIterator P = Cache.FindPkg(Pkg);
       if (P.end() != true)

+ 8 - 6
apt-pkg/contrib/cdromutl.cc

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: cdromutl.cc,v 1.11 1999/12/10 23:40:29 jgg Exp $
+// $Id: cdromutl.cc,v 1.12 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
    
    CDROM Utilities - Some functions to manipulate CDROM mounts.
@@ -19,6 +19,8 @@
 #include <apt-pkg/fileutl.h>
 #include <apt-pkg/configuration.h>
 
+#include <apti18n.h>
+    
 #include <sys/wait.h>
 #include <sys/errno.h>
 #include <sys/statvfs.h>
@@ -50,7 +52,7 @@ bool IsMounted(string &Path)
    struct stat Buf,Buf2;
    if (stat(Path.c_str(),&Buf) != 0 || 
        stat((Path + "../").c_str(),&Buf2) != 0)
-      return _error->Errno("stat","Unable to stat the mount point %s",Path.c_str());
+      return _error->Errno("stat",_("Unable to stat the mount point %s"),Path.c_str());
 
    if (Buf.st_dev == Buf2.st_dev)
       return false;
@@ -93,7 +95,7 @@ bool UnmountCdrom(string Path)
    }
 
    // Wait for mount
-   return ExecWait(Child,"mount",true);
+   return ExecWait(Child,"umount",true);
 }
 									/*}}}*/
 // MountCdrom - Mount a cdrom						/*{{{*/
@@ -144,11 +146,11 @@ bool IdentCdrom(string CD,string &Res,unsigned int Version)
 
    string StartDir = SafeGetCWD();
    if (chdir(CD.c_str()) != 0)
-      return _error->Errno("chdir","Unable to change to %s",CD.c_str());
+      return _error->Errno("chdir",_("Unable to change to %s"),CD.c_str());
    
    DIR *D = opendir(".");
    if (D == 0)
-      return _error->Errno("opendir","Unable to read %s",CD.c_str());
+      return _error->Errno("opendir",_("Unable to read %s"),CD.c_str());
       
    /* Run over the directory, we assume that the reader order will never
       change as the media is read-only. In theory if the kernel did
@@ -185,7 +187,7 @@ bool IdentCdrom(string CD,string &Res,unsigned int Version)
    {
       struct statvfs Buf;
       if (statvfs(CD.c_str(),&Buf) != 0)
-	 return _error->Errno("statfs","Failed to stat the cdrom");
+	 return _error->Errno("statfs",_("Failed to stat the cdrom"));
       
       // We use a kilobyte block size to advoid overflow
       sprintf(S,"%lu %lu",(long)(Buf.f_blocks*(Buf.f_bsize/1024)),

+ 16 - 14
apt-pkg/contrib/cmndline.cc

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: cmndline.cc,v 1.10 1999/05/14 02:57:48 jgg Exp $
+// $Id: cmndline.cc,v 1.11 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
 
    Command Line Class - Sophisticated command line parser
@@ -14,6 +14,8 @@
 #include <apt-pkg/cmndline.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/strutl.h>
+
+#include <apti18n.h>    
 									/*}}}*/
 
 // CommandLine::CommandLine - Constructor				/*{{{*/
@@ -68,7 +70,7 @@ bool CommandLine::Parse(int argc,const char **argv)
 	    Args *A;
 	    for (A = ArgList; A->end() == false && A->ShortOpt != *Opt; A++);
 	    if (A->end() == true)
-	       return _error->Error("Command line option '%c' [from %s] is not known.",*Opt,argv[I]);
+	       return _error->Error(_("Command line option '%c' [from %s] is not known."),*Opt,argv[I]);
 
 	    if (HandleOpt(I,argc,argv,Opt,A) == false)
 	       return false;
@@ -94,7 +96,7 @@ bool CommandLine::Parse(int argc,const char **argv)
 	 for (; Opt != OptEnd && *Opt != '-'; Opt++);
 
 	 if (Opt == OptEnd)
-	    return _error->Error("Command line option %s is not understood",argv[I]);
+	    return _error->Error(_("Command line option %s is not understood"),argv[I]);
 	 Opt++;
 	 
 	 for (A = ArgList; A->end() == false &&
@@ -102,7 +104,7 @@ bool CommandLine::Parse(int argc,const char **argv)
 
 	 // Failed again..
 	 if (A->end() == true && OptEnd - Opt != 1)
-	    return _error->Error("Command line option %s is not understood",argv[I]);
+	    return _error->Error(_("Command line option %s is not understood"),argv[I]);
 
 	 // The option could be a single letter option prefixed by a no-..
 	 if (A->end() == true)
@@ -110,12 +112,12 @@ bool CommandLine::Parse(int argc,const char **argv)
 	    for (A = ArgList; A->end() == false && A->ShortOpt != *Opt; A++);
 	    
 	    if (A->end() == true)
-	       return _error->Error("Command line option %s is not understood",argv[I]);
+	       return _error->Error(_("Command line option %s is not understood"),argv[I]);
 	 }
 	 
 	 // The option is not boolean
 	 if (A->IsBoolean() == false)
-	    return _error->Error("Command line option %s is not boolean",argv[I]);
+	    return _error->Error(_("Command line option %s is not boolean"),argv[I]);
 	 PreceedMatch = true;
       }
       
@@ -154,7 +156,7 @@ bool CommandLine::HandleOpt(int &I,int argc,const char *argv[],
       
       // Equals was specified but we fell off the end!
       if (Opt[1] == '=' && Argument == 0)
-	 return _error->Error("Option %s requires an argument.",argv[I]);
+	 return _error->Error(_("Option %s requires an argument."),argv[I]);
       if (Opt[1] == '=')
 	 CertainArg = true;
 	 
@@ -175,7 +177,7 @@ bool CommandLine::HandleOpt(int &I,int argc,const char *argv[],
    if ((A->Flags & HasArg) == HasArg)
    {
       if (Argument == 0)
-	 return _error->Error("Option %s requires an argument.",argv[I]);
+	 return _error->Error(_("Option %s requires an argument."),argv[I]);
       Opt += strlen(Opt);
       I += IncI;
       
@@ -189,13 +191,13 @@ bool CommandLine::HandleOpt(int &I,int argc,const char *argv[],
 	 const char *J;
 	 for (J = Argument; *J != 0 && *J != '='; J++);
 	 if (*J == 0)
-	    return _error->Error("Option %s: Configuration item sepecification must have an =<val>.",argv[I]);
+	    return _error->Error(_("Option %s: Configuration item sepecification must have an =<val>."),argv[I]);
 
 	 // = is trailing
 	 if (J[1] == 0)
 	 {
 	    if (I+1 >= argc)
-	       return _error->Error("Option %s: Configuration item sepecification must have an =<val>.",argv[I]);
+	       return _error->Error(_("Option %s: Configuration item sepecification must have an =<val>."),argv[I]);
 	    Conf->Set(string(Argument,J-Argument),string(argv[I++ +1]));
 	 }
 	 else
@@ -225,7 +227,7 @@ bool CommandLine::HandleOpt(int &I,int argc,const char *argv[],
 	 
 	 // Conversion failed and the argument was specified with an =s
 	 if (EndPtr == Argument && CertainArg == true)
-	    return _error->Error("Option %s requires an integer argument, not '%s'",argv[I],Argument);
+	    return _error->Error(_("Option %s requires an integer argument, not '%s'"),argv[I],Argument);
 
 	 // Conversion was ok, set the value and return
 	 if (EndPtr != 0 && EndPtr != Argument && *EndPtr == 0)
@@ -256,7 +258,7 @@ bool CommandLine::HandleOpt(int &I,int argc,const char *argv[],
 	    break;
 	 
 	 if (strlen(argv[I]) >= sizeof(Buffer))
-	    return _error->Error("Option '%s' is too long",argv[I]);
+	    return _error->Error(_("Option '%s' is too long"),argv[I]);
 
 	 // Skip the leading dash
 	 const char *J = argv[I];
@@ -289,7 +291,7 @@ bool CommandLine::HandleOpt(int &I,int argc,const char *argv[],
       }
 
       if (CertainArg == true)
-	 return _error->Error("Sense %s is not understood, try true or false.",Argument);
+	 return _error->Error(_("Sense %s is not understood, try true or false."),Argument);
       
       Argument = 0;
    }
@@ -339,7 +341,7 @@ bool CommandLine::DispatchArg(Dispatch *Map,bool NoMatch)
    if (Map[I].Match == 0)
    {
       if (NoMatch == true)
-	 _error->Error("Invalid operation %s",FileList[0]);
+	 _error->Error(_("Invalid operation %s"),FileList[0]);
    }
    
    return false;

+ 340 - 66
apt-pkg/contrib/configuration.cc

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: configuration.cc,v 1.14 2000/01/16 05:36:17 jgg Exp $
+// $Id: configuration.cc,v 1.15 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
 
    Configuration Class
@@ -18,9 +18,17 @@
 #include <apt-pkg/configuration.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/strutl.h>
+#include <apt-pkg/fileutl.h>
+#include <apti18n.h>
 
+#include <vector>
+#include <algorithm>
+#include <fstream>
+    
 #include <stdio.h>
-#include <fstream.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <unistd.h>
 									/*}}}*/
 
 Configuration *_config = new Configuration;
@@ -28,9 +36,45 @@ Configuration *_config = new Configuration;
 // Configuration::Configuration - Constructor				/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-Configuration::Configuration()
+Configuration::Configuration() : ToFree(true)
 {
    Root = new Item;
+}
+Configuration::Configuration(const Item *Root) : Root((Item *)Root), ToFree(false)
+{
+};
+
+									/*}}}*/
+// Configuration::~Configuration - Destructor				/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+Configuration::~Configuration()
+{
+   if (ToFree == false)
+      return;
+   
+   Item *Top = Root;
+   for (; Top != 0;)
+   {
+      if (Top->Child != 0)
+      {
+	 Top = Top->Child;
+	 continue;
+      }
+            
+      while (Top != 0 && Top->Next == 0)
+      {
+	 Item *Parent = Top->Parent;
+	 delete Top;
+	 Top = Parent;
+      }      
+      if (Top != 0)
+      {
+	 Item *Next = Top->Next;
+	 delete Top;
+	 Top = Next;
+      }
+   }
 }
 									/*}}}*/
 // Configuration::Lookup - Lookup a single item				/*{{{*/
@@ -105,9 +149,9 @@ Configuration::Item *Configuration::Lookup(const char *Name,bool Create)
 // Configuration::Find - Find a value					/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-string Configuration::Find(const char *Name,const char *Default)
+string Configuration::Find(const char *Name,const char *Default) const
 {
-   Item *Itm = Lookup(Name,false);
+   const Item *Itm = Lookup(Name);
    if (Itm == 0 || Itm->Value.empty() == true)
    {
       if (Default == 0)
@@ -124,9 +168,9 @@ string Configuration::Find(const char *Name,const char *Default)
 /* Directories are stored as the base dir in the Parent node and the
    sub directory in sub nodes with the final node being the end filename
  */
-string Configuration::FindFile(const char *Name,const char *Default)
+string Configuration::FindFile(const char *Name,const char *Default) const
 {
-   Item *Itm = Lookup(Name,false);
+   const Item *Itm = Lookup(Name);
    if (Itm == 0 || Itm->Value.empty() == true)
    {
       if (Default == 0)
@@ -135,26 +179,35 @@ string Configuration::FindFile(const char *Name,const char *Default)
 	 return Default;
    }
    
-   // Absolute path
-   if (Itm->Value[0] == '/' || Itm->Parent == 0)
-      return Itm->Value;
-   
-   // ./ is also considered absolute as is anything with ~ in it
-   if (Itm->Value[0] != 0 && 
-       ((Itm->Value[0] == '.' && Itm->Value[1] == '/') ||
-	(Itm->Value[0] == '~' && Itm->Value[1] == '/')))
-      return Itm->Value;
-   
-   if (Itm->Parent->Value.end()[-1] == '/')
-      return Itm->Parent->Value + Itm->Value;
-   else
-      return Itm->Parent->Value + '/' + Itm->Value;
+   string val = Itm->Value;
+   while (Itm->Parent != 0 && Itm->Parent->Value.empty() == false)
+   {	 
+      // Absolute
+      if (val.length() >= 1 && val[0] == '/')
+         break;
+
+      // ~/foo or ./foo 
+      if (val.length() >= 2 && (val[0] == '~' || val[0] == '.') && val[1] == '/')
+	 break;
+	 
+      // ../foo 
+      if (val.length() >= 3 && val[0] == '.' && val[1] == '.' && val[2] == '/')
+	 break;
+      
+      if (Itm->Parent->Value.end()[-1] != '/')
+	 val.insert(0, "/");
+
+      val.insert(0, Itm->Parent->Value);
+      Itm = Itm->Parent;
+   }
+
+   return val;
 }
 									/*}}}*/
 // Configuration::FindDir - Find a directory name			/*{{{*/
 // ---------------------------------------------------------------------
 /* This is like findfile execept the result is terminated in a / */
-string Configuration::FindDir(const char *Name,const char *Default)
+string Configuration::FindDir(const char *Name,const char *Default) const
 {
    string Res = FindFile(Name,Default);
    if (Res.end()[-1] != '/')
@@ -165,9 +218,9 @@ string Configuration::FindDir(const char *Name,const char *Default)
 // Configuration::FindI - Find an integer value				/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-int Configuration::FindI(const char *Name,int Default)
+int Configuration::FindI(const char *Name,int Default) const
 {
-   Item *Itm = Lookup(Name,false);
+   const Item *Itm = Lookup(Name);
    if (Itm == 0 || Itm->Value.empty() == true)
       return Default;
    
@@ -182,15 +235,68 @@ int Configuration::FindI(const char *Name,int Default)
 // Configuration::FindB - Find a boolean type				/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-bool Configuration::FindB(const char *Name,bool Default)
+bool Configuration::FindB(const char *Name,bool Default) const
 {
-   Item *Itm = Lookup(Name,false);
+   const Item *Itm = Lookup(Name);
    if (Itm == 0 || Itm->Value.empty() == true)
       return Default;
    
    return StringToBool(Itm->Value,Default);
 }
 									/*}}}*/
+// Configuration::FindAny - Find an arbitrary type			/*{{{*/
+// ---------------------------------------------------------------------
+/* a key suffix of /f, /d, /b or /i calls Find{File,Dir,B,I} */
+string Configuration::FindAny(const char *Name,const char *Default) const
+{
+   string key = Name;
+   char type = 0;
+
+   if (key.size() > 2 && key.end()[-2] == '/')
+   {
+      type = key.end()[-1];
+      key.resize(key.size() - 2);
+   }
+
+   switch (type)
+   {
+      // file
+      case 'f': 
+      return FindFile(key.c_str(), Default);
+      
+      // directory
+      case 'd': 
+      return FindDir(key.c_str(), Default);
+      
+      // bool
+      case 'b': 
+      return FindB(key, Default) ? "true" : "false";
+      
+      // int
+      case 'i': 
+      {
+	 char buf[16];
+	 snprintf(buf, sizeof(buf)-1, "%d", FindI(key, Default));
+	 return buf;
+      }
+   }
+
+   // fallback
+   return Find(Name, Default);
+}
+									/*}}}*/
+// Configuration::CndSet - Conditinal Set a value			/*{{{*/
+// ---------------------------------------------------------------------
+/* This will not overwrite */
+void Configuration::CndSet(const char *Name,string Value)
+{
+   Item *Itm = Lookup(Name,true);
+   if (Itm == 0)
+      return;
+   if (Itm->Value.empty() == true)
+      Itm->Value = Value;
+}
+									/*}}}*/
 // Configuration::Set - Set a value					/*{{{*/
 // ---------------------------------------------------------------------
 /* */
@@ -215,17 +321,73 @@ void Configuration::Set(const char *Name,int Value)
    Itm->Value = S;
 }
 									/*}}}*/
+// Configuration::Clear - Clear an entire tree				/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+void Configuration::Clear(string Name)
+{
+   Item *Top = Lookup(Name.c_str(),false);
+   if (Top == 0)
+      return;
+   
+   Top->Value = string();
+   Item *Stop = Top;
+   Top = Top->Child;
+   Stop->Child = 0;
+   for (; Top != 0;)
+   {
+      if (Top->Child != 0)
+      {
+	 Top = Top->Child;
+	 continue;
+      }
+
+      while (Top != 0 && Top->Next == 0)
+      {
+	 Item *Tmp = Top;
+	 Top = Top->Parent;
+	 delete Tmp;
+	 
+	 if (Top == Stop)
+	    return;
+      }
+      
+      Item *Tmp = Top;
+      if (Top != 0)
+	 Top = Top->Next;
+      delete Tmp;
+   }
+}
+									/*}}}*/
 // Configuration::Exists - Returns true if the Name exists		/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-bool Configuration::Exists(const char *Name)
+bool Configuration::Exists(const char *Name) const
 {
-   Item *Itm = Lookup(Name,false);
+   const Item *Itm = Lookup(Name);
    if (Itm == 0)
       return false;
    return true;
 }
 									/*}}}*/
+// Configuration::ExistsAny - Returns true if the Name, possibly	/*{{{*/
+// ---------------------------------------------------------------------
+/* qualified by /[fdbi] exists */
+bool Configuration::ExistsAny(const char *Name) const
+{
+   string key = Name;
+
+   if (key.size() > 2 && key.end()[-2] == '/' &&
+       key.find_first_of("fdbi",key.size()-1) < key.size())
+   {
+      key.resize(key.size() - 2);
+      if (Exists(key.c_str()))
+	 return true;
+   }
+
+   return Exists(Name);
+}
+									/*}}}*/
 // Configuration::Dump - Dump the config				/*{{{*/
 // ---------------------------------------------------------------------
 /* Dump the entire configuration space */
@@ -233,7 +395,7 @@ void Configuration::Dump()
 {
    /* Write out all of the configuration directives by walking the 
       configuration tree */
-   const Configuration::Item *Top = _config->Tree(0);
+   const Configuration::Item *Top = Tree(0);
    for (; Top != 0;)
    {
       clog << Top->FullTag() << " \"" << Top->Value << "\";" << endl;
@@ -248,31 +410,37 @@ void Configuration::Dump()
 	 Top = Top->Parent;
       if (Top != 0)
 	 Top = Top->Next;
-   }   
+   }
 }
 									/*}}}*/
 
 // Configuration::Item::FullTag - Return the fully scoped tag		/*{{{*/
 // ---------------------------------------------------------------------
-/* */
-string Configuration::Item::FullTag() const
+/* Stop sets an optional max recursion depth if this item is being viewed as
+   part of a sub tree. */
+string Configuration::Item::FullTag(const Item *Stop) const
 {
-   if (Parent == 0 || Parent->Parent == 0)
+   if (Parent == 0 || Parent->Parent == 0 || Parent == Stop)
       return Tag;
-   return Parent->FullTag() + "::" + Tag;
+   return Parent->FullTag(Stop) + "::" + Tag;
 }
 									/*}}}*/
 
 // ReadConfigFile - Read a configuration file				/*{{{*/
 // ---------------------------------------------------------------------
 /* The configuration format is very much like the named.conf format
-   used in bind8, in fact this routine can parse most named.conf files. */
-bool ReadConfigFile(Configuration &Conf,string FName)
-{
+   used in bind8, in fact this routine can parse most named.conf files. 
+   Sectional config files are like bind's named.conf where there are 
+   sections like 'zone "foo.org" { .. };' This causes each section to be
+   added in with a tag like "zone::foo.org" instead of being split 
+   tag/value. */
+bool ReadConfigFile(Configuration &Conf,string FName,bool AsSectional,
+		    unsigned Depth)
+{   
    // Open the stream for reading
    ifstream F(FName.c_str(),ios::in | ios::nocreate);
    if (!F != 0)
-      return _error->Errno("ifstream::ifstream","Opening configuration file %s",FName.c_str());
+      return _error->Errno("ifstream::ifstream",_("Opening configuration file %s"),FName.c_str());
    
    char Buffer[300];
    string LineBuffer;
@@ -366,7 +534,7 @@ bool ReadConfigFile(Configuration &Conf,string FName)
 	 
 	 if (InQuote == false && (*I == '{' || *I == ';' || *I == '}'))
 	 {
-	    // Put the last fragement into the buffer
+	    // Put the last fragment into the buffer
 	    char *Start = Buffer;
 	    char *Stop = I;
 	    for (; Start != I && isspace(*Start) != 0; Start++);
@@ -379,51 +547,65 @@ bool ReadConfigFile(Configuration &Conf,string FName)
 	    char TermChar = *I;
 	    memmove(Buffer,I + 1,strlen(I + 1) + 1);
 	    I = Buffer;
-
-	    // Move up a tag
-	    if (TermChar == '}')
-	    {
-	       if (StackPos == 0)
-		  ParentTag = string();
-	       else
-		  ParentTag = Stack[--StackPos];
-	    }
 	    
 	    // Syntax Error
 	    if (TermChar == '{' && LineBuffer.empty() == true)
-	       return _error->Error("Syntax error %s:%u: Block starts with no name.",FName.c_str(),CurLine);
+	       return _error->Error(_("Syntax error %s:%u: Block starts with no name."),FName.c_str(),CurLine);
 	    
+	    // No string on this line
 	    if (LineBuffer.empty() == true)
+	    {
+	       if (TermChar == '}')
+	       {
+		  if (StackPos == 0)
+		     ParentTag = string();
+		  else
+		     ParentTag = Stack[--StackPos];
+	       }
 	       continue;
-
+	    }
+	    
 	    // Parse off the tag
 	    string Tag;
 	    const char *Pos = LineBuffer.c_str();
 	    if (ParseQuoteWord(Pos,Tag) == false)
-	       return _error->Error("Syntax error %s:%u: Malformed Tag",FName.c_str(),CurLine);	    
-	    
+	       return _error->Error(_("Syntax error %s:%u: Malformed Tag"),FName.c_str(),CurLine);
+
+	    // Parse off the word
+	    string Word;
+	    if (ParseCWord(Pos,Word) == false &&
+		ParseQuoteWord(Pos,Word) == false)
+	    {
+	       if (TermChar != '{')
+	       {
+		  Word = Tag;
+		  Tag = "";
+	       }	       
+	    }
+	    if (strlen(Pos) != 0)
+	       return _error->Error(_("Syntax error %s:%u: Extra junk after value"),FName.c_str(),CurLine);
+
 	    // Go down a level
 	    if (TermChar == '{')
 	    {
 	       if (StackPos <= 100)
 		  Stack[StackPos++] = ParentTag;
+	       
+	       /* Make sectional tags incorperate the section into the
+	          tag string */
+	       if (AsSectional == true && Word.empty() == false)
+	       {
+		  Tag += "::" ;
+		  Tag += Word;
+		  Word = "";
+	       }
+	       
 	       if (ParentTag.empty() == true)
 		  ParentTag = Tag;
 	       else
 		  ParentTag += string("::") + Tag;
 	       Tag = string();
 	    }
-
-	    // Parse off the word
-	    string Word;
-	    if (ParseCWord(Pos,Word) == false)
-	    {
-	       if (TermChar != '{')
-	       {
-		  Word = Tag;
-		  Tag = "";
-	       }	       
-	    }
 	    
 	    // Generate the item name
 	    string Item;
@@ -437,11 +619,50 @@ bool ReadConfigFile(Configuration &Conf,string FName)
 		  Item = ParentTag;
 	    }
 	    
-	    // Set the item in the configuration class
-	    Conf.Set(Item,Word);
-			    
+	    // Specials
+	    if (Tag.length() >= 1 && Tag[0] == '#')
+	    {
+	       if (ParentTag.empty() == false)
+		  return _error->Error(_("Syntax error %s:%u: Directives can only be done at the top level"),FName.c_str(),CurLine);
+	       Tag.erase(Tag.begin());
+	       if (Tag == "clear")
+		  Conf.Clear(Word);
+	       else if (Tag == "include")
+	       {
+		  if (Depth > 10)
+		     return _error->Error(_("Syntax error %s:%u: Too many nested includes"),FName.c_str(),CurLine);
+		  if (Word.length() > 2 && Word.end()[-1] == '/')
+		  {
+		     if (ReadConfigDir(Conf,Word,AsSectional,Depth+1) == false)
+			return _error->Error(_("Syntax error %s:%u: Included from here"),FName.c_str(),CurLine);
+		  }
+		  else
+		  {
+		     if (ReadConfigFile(Conf,Word,AsSectional,Depth+1) == false)
+			return _error->Error(_("Syntax error %s:%u: Included from here"),FName.c_str(),CurLine);
+		  }		  
+	       }
+	       else
+		  return _error->Error(_("Syntax error %s:%u: Unsupported directive '%s'"),FName.c_str(),CurLine,Tag.c_str());
+	    }
+	    else
+	    {
+	       // Set the item in the configuration class
+	       Conf.Set(Item,Word);
+	    }
+	    
 	    // Empty the buffer
 	    LineBuffer = string();
+	    
+	    // Move up a tag, but only if there is no bit to parse
+	    if (TermChar == '}')
+	    {
+	       if (StackPos == 0)
+		  ParentTag = string();
+	       else
+		  ParentTag = Stack[--StackPos];
+	    }
+	    
 	 }
 	 else
 	    I++;
@@ -453,7 +674,60 @@ bool ReadConfigFile(Configuration &Conf,string FName)
 	 LineBuffer += " ";
       LineBuffer += Stripd;
    }
+
+   if (LineBuffer.empty() == false)
+      return _error->Error(_("Syntax error %s:%u: Extra junk at end of file"),FName.c_str(),CurLine);
+   return true;
+}
+									/*}}}*/
+// ReadConfigDir - Read a directory of config files			/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool ReadConfigDir(Configuration &Conf,string Dir,bool AsSectional,
+		    unsigned Depth)
+{   
+   static const char *BadExts[] = {".disabled",".dpkg-old",".dpkg-dist",
+   				   ".rpmsave",".rpmorig","~",",v",0};
+   
+   DIR *D = opendir(Dir.c_str());
+   if (D == 0)
+      return _error->Errno("opendir",_("Unable to read %s"),Dir.c_str());
+
+   vector<string> List;
+   
+   for (struct dirent *Ent = readdir(D); Ent != 0; Ent = readdir(D))
+   {
+      if (strcmp(Ent->d_name,".") == 0 ||
+	  strcmp(Ent->d_name,"..") == 0)
+	 continue;
+      
+      // Skip bad extensions
+      const char **I;
+      for (I = BadExts; *I != 0; I++)
+      {
+	 if (strcmp(Ent->d_name + strlen(Ent->d_name) - strlen(*I),*I) == 0)
+	    break;
+      }
+      
+      if (*I != 0)
+	 continue;
+      
+      // Make sure it is a file and not something else
+      string File = flCombine(Dir,Ent->d_name);
+      struct stat St;
+      if (stat(File.c_str(),&St) != 0 || S_ISREG(St.st_mode) == 0)
+	 continue;
+      
+      List.push_back(File);      
+   }   
+   closedir(D);
    
+   sort(List.begin(),List.end());
+
+   // Read the files
+   for (vector<string>::const_iterator I = List.begin(); I != List.end(); I++)
+      if (ReadConfigFile(Conf,*I,AsSectional,Depth) == false)
+	 return false;
    return true;
 }
 									/*}}}*/

+ 39 - 18
apt-pkg/contrib/configuration.h

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: configuration.h,v 1.11 1999/04/03 00:34:33 jgg Exp $
+// $Id: configuration.h,v 1.12 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
 
    Configuration Class
@@ -36,6 +36,8 @@
 
 class Configuration
 {
+   public:
+   
    struct Item
    {
       string Value;
@@ -44,42 +46,61 @@ class Configuration
       Item *Child;
       Item *Next;
       
-      string FullTag() const;
+      string FullTag(const Item *Stop = 0) const;
       
       Item() : Parent(0), Child(0), Next(0) {};
    };
+   
+   private:
+   
    Item *Root;
+   bool ToFree;
    
    Item *Lookup(Item *Head,const char *S,unsigned long Len,bool Create);
-   Item *Lookup(const char *Name,bool Create);
-      
+   Item *Lookup(const char *Name,bool Create);   
+   inline const Item *Lookup(const char *Name) const
+   {
+      return ((Configuration *)this)->Lookup(Name,false);
+   }  
+   
    public:
 
-   string Find(const char *Name,const char *Default = 0);
-   string Find(string Name,const char *Default = 0) {return Find(Name.c_str(),Default);};
-   string FindFile(const char *Name,const char *Default = 0);
-   string FindDir(const char *Name,const char *Default = 0);
-   int FindI(const char *Name,int Default = 0);
-   int FindI(string Name,bool Default = 0) {return FindI(Name.c_str(),Default);};
-   bool FindB(const char *Name,bool Default = false);
-   bool FindB(string Name,bool Default = false) {return FindB(Name.c_str(),Default);};
+   string Find(const char *Name,const char *Default = 0) const;
+   string Find(string Name,const char *Default = 0) const {return Find(Name.c_str(),Default);};
+   string FindFile(const char *Name,const char *Default = 0) const;
+   string FindDir(const char *Name,const char *Default = 0) const;
+   int FindI(const char *Name,int Default = 0) const;
+   int FindI(string Name,bool Default = 0) const {return FindI(Name.c_str(),Default);};
+   bool FindB(const char *Name,bool Default = false) const;
+   bool FindB(string Name,bool Default = false) const {return FindB(Name.c_str(),Default);};
+   string FindAny(const char *Name,const char *Default = 0) const;
 	      
    inline void Set(string Name,string Value) {Set(Name.c_str(),Value);};
+   void CndSet(const char *Name,string Value);
    void Set(const char *Name,string Value);
    void Set(const char *Name,int Value);   
    
-   inline bool Exists(string Name) {return Exists(Name.c_str());};
-   bool Exists(const char *Name);
-      
-   inline const Item *Tree(const char *Name) {return Lookup(Name,false);};
+   inline bool Exists(string Name) const {return Exists(Name.c_str());};
+   bool Exists(const char *Name) const;
+   bool ExistsAny(const char *Name) const;
 
-   void Dump();
+   void Clear(string Name);
    
+   inline const Item *Tree(const char *Name) const {return Lookup(Name);};
+
+   void Dump();
+
+   Configuration(const Item *Root);
    Configuration();
+   ~Configuration();
 };
 
 extern Configuration *_config;
 
-bool ReadConfigFile(Configuration &Conf,string File);
+bool ReadConfigFile(Configuration &Conf,string FName,bool AsSectional = false,
+		    unsigned Depth = 0);
+
+bool ReadConfigDir(Configuration &Conf,string Dir,bool AsSectional = false,
+		    unsigned Depth = 0);
 
 #endif

+ 2 - 2
apt-pkg/contrib/error.cc

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: error.cc,v 1.8 1999/08/08 07:24:54 jgg Exp $
+// $Id: error.cc,v 1.9 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
    
    Global Erorr Class - Global error mechanism
@@ -34,7 +34,7 @@
    is compiled to be thread safe otherwise a non-safe version is used. A
    Per-Thread error object is maintained in much the same manner as libc
    manages errno */
-#if _POSIX_THREADS == 1 && defined(HAVE_PTHREAD)
+#if defined(_POSIX_THREADS) && defined(HAVE_PTHREAD)
  #include <pthread.h>
 
  static pthread_key_t ErrorKey;

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

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: error.h,v 1.6 1999/01/18 06:20:08 jgg Exp $
+// $Id: error.h,v 1.7 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
    
    Global Erorr Class - Global error mechanism
@@ -44,6 +44,15 @@
 #pragma interface "apt-pkg/error.h"
 #endif 
 
+#ifdef __GNUG__
+// Methods have a hidden this parameter that is visible to this attribute
+#define APT_MFORMAT1 __attribute__ ((format (printf, 2, 3)))
+#define APT_MFORMAT2 __attribute__ ((format (printf, 3, 4)))
+#else
+#define APT_MFORMAT1
+#define APT_MFORMAT2    
+#endif    
+    
 #include <string>
 
 class GlobalError
@@ -62,13 +71,13 @@ class GlobalError
    public:
 
    // Call to generate an error from a library call.
-   bool Errno(const char *Function,const char *Description,...);
-   bool WarningE(const char *Function,const char *Description,...);
+   bool Errno(const char *Function,const char *Description,...) APT_MFORMAT2;
+   bool WarningE(const char *Function,const char *Description,...) APT_MFORMAT2;
 
    /* A warning should be considered less severe than an error, and may be
       ignored by the client. */
-   bool Error(const char *Description,...);
-   bool Warning(const char *Description,...);
+   bool Error(const char *Description,...) APT_MFORMAT1;
+   bool Warning(const char *Description,...) APT_MFORMAT1;
 
    // Simple accessors
    inline bool PendingError() {return PendingFlag;};
@@ -86,4 +95,7 @@ class GlobalError
 GlobalError *_GetErrorObj();
 #define _error _GetErrorObj()
 
+#undef APT_MFORMAT1
+#undef APT_MFORMAT2
+
 #endif

+ 81 - 26
apt-pkg/contrib/fileutl.cc

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: fileutl.cc,v 1.34 2000/01/17 07:11:49 jgg Exp $
+// $Id: fileutl.cc,v 1.35 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
    
    File Utilities
@@ -19,6 +19,9 @@
 #endif 
 #include <apt-pkg/fileutl.h>
 #include <apt-pkg/error.h>
+#include <apt-pkg/sptr.h>
+
+#include <apti18n.h>
 
 #include <unistd.h>
 #include <fcntl.h>
@@ -39,7 +42,7 @@ bool CopyFile(FileFd &From,FileFd &To)
       return false;
    
    // Buffered copy between fds
-   unsigned char *Buf = new unsigned char[64000];
+   SPtrArray<unsigned char> Buf = new unsigned char[64000];
    unsigned long Size = From.Size();
    while (Size != 0)
    {
@@ -49,15 +52,11 @@ bool CopyFile(FileFd &From,FileFd &To)
       
       if (From.Read(Buf,ToRead) == false || 
 	  To.Write(Buf,ToRead) == false)
-      {
-	 delete [] Buf;
 	 return false;
-      }
       
       Size -= ToRead;
    }
 
-   delete [] Buf;
    return true;   
 }
 									/*}}}*/
@@ -72,11 +71,22 @@ int GetLock(string File,bool Errors)
    int FD = open(File.c_str(),O_RDWR | O_CREAT | O_TRUNC,0640);
    if (FD < 0)
    {
+      // Read only .. cant have locking problems there.
+      if (errno == EROFS)
+      {
+	 _error->Warning(_("Not using locking for read only lock file %s"),File.c_str());
+	 return dup(0);       // Need something for the caller to close
+      }
+      
       if (Errors == true)
-	 _error->Errno("open","Could not open lock file %s",File.c_str());
+	 _error->Errno("open",_("Could not open lock file %s"),File.c_str());
+
+      // Feh.. We do this to distinguish the lock vs open case..
+      errno = EPERM;
       return -1;
    }
-   
+   SetCloseExec(FD,true);
+      
    // Aquire a write lock
    struct flock fl;
    fl.l_type = F_WRLCK;
@@ -87,12 +97,15 @@ int GetLock(string File,bool Errors)
    {
       if (errno == ENOLCK)
       {
-	 _error->Warning("Not using locking for nfs mounted lock file %s",File.c_str());
-	 return true;
+	 _error->Warning(_("Not using locking for nfs mounted lock file %s"),File.c_str());
+	 return dup(0);       // Need something for the caller to close	 
       }      
       if (Errors == true)
-	 _error->Errno("open","Could not get lock %s",File.c_str());
+	 _error->Errno("open",_("Could not get lock %s"),File.c_str());
+      
+      int Tmp = errno;
       close(FD);
+      errno = Tmp;
       return -1;
    }
 
@@ -150,6 +163,18 @@ string flNotFile(string File)
    return string(File,0,Res);
 }
 									/*}}}*/
+// flExtension - Return the extension for the file			/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+string flExtension(string File)
+{
+   string::size_type Res = File.rfind('.');
+   if (Res == string::npos)
+      return File;
+   Res++;
+   return string(File,Res,Res - File.length());
+}
+									/*}}}*/
 // flNoLink - If file is a symlink then deref it			/*{{{*/
 // ---------------------------------------------------------------------
 /* If the name is not a link then the returned path is the input. */
@@ -189,6 +214,24 @@ string flNoLink(string File)
    }   
 }
 									/*}}}*/
+// flCombine - Combine a file and a directory				/*{{{*/
+// ---------------------------------------------------------------------
+/* If the file is an absolute path then it is just returned, otherwise
+   the directory is pre-pended to it. */
+string flCombine(string Dir,string File)
+{
+   if (File.empty() == true)
+      return string();
+   
+   if (File[0] == '/' || Dir.empty() == true)
+      return File;
+   if (File.length() >= 2 && File[0] == '.' && File[1] == '/')
+      return File;
+   if (Dir[Dir.length()-1] == '/')
+      return Dir + File;
+   return Dir + '/' + File;
+}
+									/*}}}*/
 // SetCloseExec - Set the close on exec flag				/*{{{*/
 // ---------------------------------------------------------------------
 /* */
@@ -216,7 +259,7 @@ void SetNonBlock(int Fd,bool Block)
 									/*}}}*/
 // WaitFd - Wait for a FD to become readable				/*{{{*/
 // ---------------------------------------------------------------------
-/* This waits for a FD to become readable using select. It is usefull for
+/* This waits for a FD to become readable using select. It is useful for
    applications making use of non-blocking sockets. The timeout is 
    in seconds. */
 bool WaitFd(int Fd,bool write,unsigned long timeout)
@@ -309,7 +352,7 @@ bool ExecWait(int Pid,const char *Name,bool Reap)
       if (Reap == true)
 	 return false;
       
-      return _error->Error("Waited, for %s but it wasn't there",Name);
+      return _error->Error(_("Waited, for %s but it wasn't there"),Name);
    }
 
    
@@ -319,12 +362,12 @@ bool ExecWait(int Pid,const char *Name,bool Reap)
       if (Reap == true)
 	 return false;
       if (WIFSIGNALED(Status) != 0 && WTERMSIG(Status) == SIGSEGV)
-	 return _error->Error("Sub-process %s recieved a segmentation fault.",Name);
+	 return _error->Error(_("Sub-process %s received a segmentation fault."),Name);
 
       if (WIFEXITED(Status) != 0)
-	 return _error->Error("Sub-process %s returned an error code (%u)",Name,WEXITSTATUS(Status));
+	 return _error->Error(_("Sub-process %s returned an error code (%u)"),Name,WEXITSTATUS(Status));
       
-      return _error->Error("Sub-process %s exited unexpectedly",Name);
+      return _error->Error(_("Sub-process %s exited unexpectedly"),Name);
    }      
    
    return true;
@@ -363,7 +406,7 @@ bool FileFd::Open(string FileName,OpenMode Mode, unsigned long Perms)
    }  
 
    if (iFd < 0)
-      return _error->Errno("open","Could not open file %s",FileName.c_str());
+      return _error->Errno("open",_("Could not open file %s"),FileName.c_str());
    
    this->FileName = FileName;
    SetCloseExec(iFd,true);
@@ -395,7 +438,7 @@ bool FileFd::Read(void *To,unsigned long Size,bool AllowEof)
       if (Res < 0)
       {
 	 Flags |= Fail;
-	 return _error->Errno("read","Read error");
+	 return _error->Errno("read",_("Read error"));
       }
       
       To = (char *)To + Res;
@@ -414,7 +457,7 @@ bool FileFd::Read(void *To,unsigned long Size,bool AllowEof)
    }
    
    Flags |= Fail;
-   return _error->Error("read, still have %u to read but none left",Size);
+   return _error->Error(_("read, still have %lu to read but none left"),Size);
 }
 									/*}}}*/
 // FileFd::Write - Write to the file					/*{{{*/
@@ -432,7 +475,7 @@ bool FileFd::Write(const void *From,unsigned long Size)
       if (Res < 0)
       {
 	 Flags |= Fail;
-	 return _error->Errno("write","Write error");
+	 return _error->Errno("write",_("Write error"));
       }
       
       From = (char *)From + Res;
@@ -444,7 +487,7 @@ bool FileFd::Write(const void *From,unsigned long Size)
       return true;
    
    Flags |= Fail;
-   return _error->Error("write, still have %u to write but couldn't",Size);
+   return _error->Error(_("write, still have %lu to write but couldn't"),Size);
 }
 									/*}}}*/
 // FileFd::Seek - Seek in the file					/*{{{*/
@@ -455,7 +498,7 @@ bool FileFd::Seek(unsigned long To)
    if (lseek(iFd,To,SEEK_SET) != (signed)To)
    {
       Flags |= Fail;
-      return _error->Error("Unable to seek to %u",To);
+      return _error->Error("Unable to seek to %lu",To);
    }
    
    return true;
@@ -469,7 +512,7 @@ bool FileFd::Skip(unsigned long Over)
    if (lseek(iFd,Over,SEEK_CUR) < 0)
    {
       Flags |= Fail;
-      return _error->Error("Unable to seek ahead %u",Over);
+      return _error->Error("Unable to seek ahead %lu",Over);
    }
    
    return true;
@@ -483,7 +526,7 @@ bool FileFd::Truncate(unsigned long To)
    if (ftruncate(iFd,To) != 0)
    {
       Flags |= Fail;
-      return _error->Error("Unable to truncate to %u",To);
+      return _error->Error("Unable to truncate to %lu",To);
    }
    
    return true;
@@ -519,13 +562,25 @@ bool FileFd::Close()
    bool Res = true;
    if ((Flags & AutoClose) == AutoClose)
       if (iFd >= 0 && close(iFd) != 0)
-	 Res &= _error->Errno("close","Problem closing the file");
+	 Res &= _error->Errno("close",_("Problem closing the file"));
    iFd = -1;
    
    if ((Flags & Fail) == Fail && (Flags & DelOnFail) == DelOnFail &&
        FileName.empty() == false)
       if (unlink(FileName.c_str()) != 0)
-	 Res &= _error->Warning("unlnk","Problem unlinking the file");
+	 Res &= _error->WarningE("unlnk",_("Problem unlinking the file"));
    return Res;
 }
 									/*}}}*/
+// FileFd::Sync - Sync the file						/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool FileFd::Sync()
+{
+#ifdef _POSIX_SYNCHRONIZED_IO
+   if (fsync(iFd) != 0)
+      return _error->Errno("sync",_("Problem syncing the file"));
+#endif
+   return true;
+}
+									/*}}}*/

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

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: fileutl.h,v 1.22 1999/09/30 06:30:34 jgg Exp $
+// $Id: fileutl.h,v 1.23 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
    
    File Utilities
@@ -49,7 +49,8 @@ class FileFd
    unsigned long Size();
    bool Open(string FileName,OpenMode Mode,unsigned long Perms = 0666);
    bool Close();
-
+   bool Sync();
+   
    // Simple manipulators
    inline int Fd() {return iFd;};
    inline void Fd(int fd) {iFd = fd;};
@@ -84,5 +85,7 @@ bool ExecWait(int Pid,const char *Name,bool Reap = false);
 string flNotDir(string File);
 string flNotFile(string File);
 string flNoLink(string File);
+string flExtension(string File);
+string flCombine(string Dir,string File);
 
 #endif

+ 2 - 2
apt-pkg/contrib/md5.h

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: md5.h,v 1.4 1999/08/02 03:07:47 jgg Exp $
+// $Id: md5.h,v 1.5 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
    
    MD5SumValue - Storage for a MD5Sum
@@ -33,7 +33,7 @@ class MD5Summation;
 
 class MD5SumValue
 {
-   friend MD5Summation;
+   friend class MD5Summation;
    unsigned char Sum[4*4];
    
    public:

+ 15 - 8
apt-pkg/contrib/mmap.cc

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: mmap.cc,v 1.20 1999/10/02 04:14:54 jgg Exp $
+// $Id: mmap.cc,v 1.21 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
    
    MMap Class - Provides 'real' mmap or a faked mmap using read().
@@ -29,6 +29,8 @@
 #include <apt-pkg/mmap.h>
 #include <apt-pkg/error.h>
 
+#include <apti18n.h>
+
 #include <sys/mman.h>
 #include <sys/stat.h>
 #include <unistd.h>
@@ -77,12 +79,12 @@ bool MMap::Map(FileFd &Fd)
       Map = MAP_PRIVATE;
    
    if (iSize == 0)
-      return _error->Error("Can't mmap an empty file");
+      return _error->Error(_("Can't mmap an empty file"));
    
    // Map it.
    Base = mmap(0,iSize,Prot,Map,Fd.Fd(),0);
    if (Base == (void *)-1)
-      return _error->Errno("mmap","Couldn't make mmap of %u bytes",iSize);
+      return _error->Errno("mmap",_("Couldn't make mmap of %lu bytes"),iSize);
 
    return true;
 }
@@ -102,6 +104,7 @@ bool MMap::Close(bool DoSync)
       _error->Warning("Unable to munmap");
    
    iSize = 0;
+   Base = 0;
    return true;
 }
 									/*}}}*/
@@ -150,9 +153,15 @@ DynamicMMap::DynamicMMap(FileFd &F,unsigned long Flags,unsigned long WorkSpace)
       return;
    
    unsigned long EndOfFile = Fd->Size();
-   Fd->Seek(WorkSpace);
-   char C = 0;
-   Fd->Write(&C,sizeof(C));
+   if (EndOfFile > WorkSpace)
+      WorkSpace = EndOfFile;
+   else
+   {
+      Fd->Seek(WorkSpace);
+      char C = 0;
+      Fd->Write(&C,sizeof(C));
+   }
+   
    Map(F);
    iSize = EndOfFile;
 }
@@ -182,11 +191,9 @@ DynamicMMap::~DynamicMMap()
    }
    
    unsigned long EndOfFile = iSize;
-   Sync();
    iSize = WorkSpace;
    Close(false);
    ftruncate(Fd->Fd(),EndOfFile);
-   Fd->Close();
 }  
 									/*}}}*/
 // DynamicMMap::RawAllocate - Allocate a raw chunk of unaligned space	/*{{{*/

+ 10 - 4
apt-pkg/contrib/progress.cc

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: progress.cc,v 1.9 2000/06/05 04:22:25 jgg Exp $
+// $Id: progress.cc,v 1.10 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
    
    OpProgress - Operation Progress
@@ -14,6 +14,9 @@
 #include <apt-pkg/progress.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/configuration.h>
+
+#include <apti18n.h>
+    
 #include <stdio.h>
 									/*}}}*/
 
@@ -110,6 +113,9 @@ bool OpProgress::CheckChange(float Interval)
    if ((int)LastPercent == (int)Percent)
       return false;
    
+   if (Interval == 0)
+      return false;
+   
    // Check time delta
    struct timeval Now;
    gettimeofday(&Now,0);
@@ -142,9 +148,9 @@ void OpTextProgress::Done()
    {
       char S[300];
       if (_error->PendingError() == true)
-	 snprintf(S,sizeof(S),"\r%s... Error!",OldOp.c_str());
+	 snprintf(S,sizeof(S),_("\r%s... Error!"),OldOp.c_str());
       else
-	 snprintf(S,sizeof(S),"\r%s... Done",OldOp.c_str());
+	 snprintf(S,sizeof(S),_("\r%s... Done"),OldOp.c_str());
       Write(S);
       cout << endl;
       OldOp = string();
@@ -162,7 +168,7 @@ void OpTextProgress::Done()
 /* */
 void OpTextProgress::Update()
 {
-   if (CheckChange() == false)
+   if (CheckChange((NoUpdate == true?0:0.7)) == false)
       return;
    
    // No percent spinner

+ 66 - 0
apt-pkg/contrib/sptr.h

@@ -0,0 +1,66 @@
+// -*- mode: cpp; mode: fold -*-
+// Description								/*{{{*/
+// $Id: sptr.h,v 1.2 2001/02/20 07:03:17 jgg Exp $
+/* ######################################################################
+   
+   Trivial non-ref counted 'smart pointer'
+   
+   This is really only good to eliminate 
+     { 
+       delete Foo;
+       return;
+     }
+   
+   Blocks from functions.
+   
+   I think G++ has become good enough that doing this won't have much
+   code size implications.
+   
+   ##################################################################### */
+									/*}}}*/
+#ifndef SMART_POINTER_H
+#define SMART_POINTER_H
+
+template <class T>
+class SPtr
+{
+   public:
+   T *Ptr;
+   
+   inline T *operator ->() {return Ptr;};
+   inline T &operator *() {return *Ptr;};
+   inline operator T *() {return Ptr;};
+   inline operator void *() {return Ptr;};
+   inline T *UnGuard() {T *Tmp = Ptr; Ptr = 0; return Tmp;};
+   inline void operator =(T *N) {Ptr = N;};      
+   inline bool operator ==(T *lhs) const {return Ptr == lhs;};
+   inline bool operator !=(T *lhs) const {return Ptr != lhs;};
+   inline T*Get() {return Ptr;};
+      
+   inline SPtr(T *Ptr) : Ptr(Ptr) {};
+   inline SPtr() : Ptr(0) {};
+   inline ~SPtr() {delete Ptr;};
+};
+
+template <class T>
+class SPtrArray
+{
+   public:
+   T *Ptr;
+   
+   inline T &operator *() {return *Ptr;};
+   inline operator T *() {return Ptr;};
+   inline operator void *() {return Ptr;};
+   inline T *UnGuard() {T *Tmp = Ptr; Ptr = 0; return Tmp;};
+   inline T &operator [](signed long I) {return Ptr[I];};
+   inline void operator =(T *N) {Ptr = N;};
+   inline bool operator ==(T *lhs) const {return Ptr == lhs;};
+   inline bool operator !=(T *lhs) const {return Ptr != lhs;};
+   inline T*Get() {return Ptr;};
+   
+   inline SPtrArray(T *Ptr) : Ptr(Ptr) {};
+   inline SPtrArray() : Ptr(0) {};
+   inline ~SPtrArray() {delete []Ptr;};
+};
+
+#endif

+ 153 - 10
apt-pkg/contrib/strutl.cc

@@ -1,12 +1,12 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: strutl.cc,v 1.34 2000/01/16 05:36:17 jgg Exp $
+// $Id: strutl.cc,v 1.35 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
 
-   String Util - Some usefull string functions.
+   String Util - Some useful string functions.
 
-   These have been collected from here and there to do all sorts of usefull
-   things to strings. They are usefull in file parsers, URI handlers and
+   These have been collected from here and there to do all sorts of useful
+   things to strings. They are useful in file parsers, URI handlers and
    especially in APT methods.   
    
    This source is placed in the Public Domain, do with it what you will
@@ -21,12 +21,17 @@
 
 #include <apt-pkg/strutl.h>
 #include <apt-pkg/fileutl.h>
+#include <apt-pkg/error.h>
 
+#include <apti18n.h>
+    
 #include <ctype.h>
 #include <string.h>
 #include <stdio.h>
 #include <unistd.h>
+#include <regex.h>
 #include <errno.h>
+#include <stdarg.h>
 									/*}}}*/
 
 // strstrip - Remove white space from the front and back of a string	/*{{{*/
@@ -147,9 +152,9 @@ bool ParseQuoteWord(const char *&String,string &Res)
 									/*}}}*/
 // ParseCWord - Parses a string like a C "" expression			/*{{{*/
 // ---------------------------------------------------------------------
-/* This expects a series of space seperated strings enclosed in ""'s. 
+/* This expects a series of space separated strings enclosed in ""'s. 
    It concatenates the ""'s into a single string. */
-bool ParseCWord(const char *String,string &Res)
+bool ParseCWord(const char *&String,string &Res)
 {
    // Skip leading whitespace
    const char *C = String;
@@ -180,9 +185,10 @@ bool ParseCWord(const char *String,string &Res)
       if (isspace(*C) == 0)
 	 return false;
       *Buf++ = ' ';
-   }   
+   }
    *Buf = 0;
    Res = Buffer;
+   String = C;
    return true;
 }
 									/*}}}*/
@@ -325,6 +331,13 @@ string SubstVar(string Str,string Subst,string Contents)
    
    return Temp + string(Str,OldPos);
 }
+
+string SubstVar(string Str,const struct SubstVar *Vars)
+{
+   for (; Vars->Subst != 0; Vars++)
+      Str = SubstVar(Str,Vars->Subst,*Vars->Contents);
+   return Str;
+}
 									/*}}}*/
 // URItoFileName - Convert the uri into a unique file name		/*{{{*/
 // ---------------------------------------------------------------------
@@ -548,9 +561,11 @@ bool ReadMessages(int Fd, vector<string> &List)
 	 return false;
       
       // No data
-      if (Res <= 0)
+      if (Res < 0 && errno == EAGAIN)
 	 return true;
-
+      if (Res < 0)
+	 return false;
+			      
       End += Res;
       
       // Look for the end of the message
@@ -749,6 +764,121 @@ bool Hex2Num(const char *Start,const char *End,unsigned char *Num,
    return true;
 }
 									/*}}}*/
+// TokSplitString - Split a string up by a given token			/*{{{*/
+// ---------------------------------------------------------------------
+/* This is intended to be a faster splitter, it does not use dynamic
+   memories. Input is changed to insert nulls at each token location. */
+bool TokSplitString(char Tok,char *Input,char **List,
+		    unsigned long ListMax)
+{
+   // Strip any leading spaces
+   char *Start = Input;
+   char *Stop = Start + strlen(Start);
+   for (; *Start != 0 && isspace(*Start) != 0; Start++);
+
+   unsigned long Count = 0;
+   char *Pos = Start;
+   while (Pos != Stop)
+   {
+      // Skip to the next Token
+      for (; Pos != Stop && *Pos != Tok; Pos++);
+      
+      // Back remove spaces
+      char *End = Pos;
+      for (; End > Start && (End[-1] == Tok || isspace(End[-1]) != 0); End--);
+      *End = 0;
+      
+      List[Count++] = Start;
+      if (Count >= ListMax)
+      {
+	 List[Count-1] = 0;
+	 return false;
+      }
+      
+      // Advance pos
+      for (; Pos != Stop && (*Pos == Tok || isspace(*Pos) != 0 || *Pos == 0); Pos++);
+      Start = Pos;
+   }
+   
+   List[Count] = 0;
+   return true;
+}
+									/*}}}*/
+// RegexChoice - Simple regex list/list matcher				/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+unsigned long RegexChoice(RxChoiceList *Rxs,const char **ListBegin,
+		      const char **ListEnd)
+{
+   for (RxChoiceList *R = Rxs; R->Str != 0; R++)
+      R->Hit = false;
+
+   unsigned long Hits = 0;
+   for (; ListBegin != ListEnd; ListBegin++)
+   {
+      // Check if the name is a regex
+      const char *I;
+      bool Regex = true;
+      for (I = *ListBegin; *I != 0; I++)
+	 if (*I == '.' || *I == '?' || *I == '*' || *I == '|')
+	    break;
+      if (*I == 0)
+	 Regex = false;
+	 
+      // Compile the regex pattern
+      regex_t Pattern;
+      if (Regex == true)
+	 if (regcomp(&Pattern,*ListBegin,REG_EXTENDED | REG_ICASE |
+		     REG_NOSUB) != 0)
+	    Regex = false;
+	 
+      // Search the list
+      bool Done = false;
+      for (RxChoiceList *R = Rxs; R->Str != 0; R++)
+      {
+	 if (R->Str[0] == 0)
+	    continue;
+	 
+	 if (strcasecmp(R->Str,*ListBegin) != 0)
+	 {
+	    if (Regex == false)
+	       continue;
+	    if (regexec(&Pattern,R->Str,0,0,0) != 0)
+	       continue;
+	 }
+	 Done = true;
+	 
+	 if (R->Hit == false)
+	    Hits++;
+	 
+	 R->Hit = true;
+      }
+      
+      if (Regex == true)
+	 regfree(&Pattern);
+      
+      if (Done == false)
+	 _error->Warning(_("Selection %s not found"),*ListBegin);
+   }
+   
+   return Hits;
+}
+									/*}}}*/
+// ioprintf - C format string outputter to C++ iostreams		/*{{{*/
+// ---------------------------------------------------------------------
+/* This is used to make the internationalization strinc easier to translate
+ and to allow reordering of parameters */
+void ioprintf(ostream &out,const char *format,...) 
+{
+   va_list args;
+   va_start(args,format);
+   
+   // sprintf the description
+   char S[400];
+   vsnprintf(S,sizeof(S),format,args);
+   out << S;
+}
+									/*}}}*/
 
 // URI::CopyFrom - Copy from an object					/*{{{*/
 // ---------------------------------------------------------------------
@@ -757,7 +887,7 @@ void URI::CopyFrom(string U)
 {
    string::const_iterator I = U.begin();
 
-   // Locate the first colon, this seperates the scheme
+   // Locate the first colon, this separates the scheme
    for (; I < U.end() && *I != ':' ; I++);
    string::const_iterator FirstColon = I;
 
@@ -912,3 +1042,16 @@ URI::operator string()
    return Res;
 }
 									/*}}}*/
+// URI::SiteOnly - Return the schema and site for the URI		/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+string URI::SiteOnly(string URI)
+{
+   ::URI U(URI);
+   U.User = string();
+   U.Password = string();
+   U.Path = string();
+   U.Port = 0;
+   return U;
+}
+									/*}}}*/

+ 34 - 4
apt-pkg/contrib/strutl.h

@@ -1,9 +1,9 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: strutl.h,v 1.15 1999/08/02 03:07:48 jgg Exp $
+// $Id: strutl.h,v 1.16 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
 
-   String Util - These are some usefull string functions
+   String Util - These are some useful string functions
    
    _strstrip is a function to remove whitespace from the front and end
    of a string.
@@ -25,15 +25,21 @@
 #include <vector>
 #include <time.h>
 
+#ifdef __GNUG__
+// Methods have a hidden this parameter that is visible to this attribute
+#define APT_FORMAT2 __attribute__ ((format (printf, 2, 3)))
+#else
+#define APT_FORMAT2
+#endif    
+    
 char *_strstrip(char *String);
 char *_strtabexpand(char *String,size_t Len);
 bool ParseQuoteWord(const char *&String,string &Res);
-bool ParseCWord(const char *String,string &Res);
+bool ParseCWord(const char *&String,string &Res);
 string QuoteString(string Str,const char *Bad);
 string DeQuoteString(string Str);
 string SizeToStr(double Bytes);
 string TimeToStr(unsigned long Sec);
-string SubstVar(string Str,string Subst,string Contents);
 string Base64Encode(string Str);
 string URItoFileName(string URI);
 string TimeRFC1123(time_t Date);
@@ -44,6 +50,9 @@ bool ReadMessages(int Fd, vector<string> &List);
 bool StrToNum(const char *Str,unsigned long &Res,unsigned Len,unsigned Base = 0);
 bool Hex2Num(const char *Start,const char *End,unsigned char *Num,
 	     unsigned int Length);
+bool TokSplitString(char Tok,char *Input,char **List,
+		    unsigned long ListMax);
+void ioprintf(ostream &out,const char *format,...) APT_FORMAT2;
 
 int stringcmp(const char *A,const char *AEnd,const char *B,const char *BEnd);
 inline int stringcmp(const char *A,const char *AEnd,const char *B) {return stringcmp(A,AEnd,B,B+strlen(B));};
@@ -51,6 +60,7 @@ inline int stringcmp(string A,const char *B) {return stringcmp(A.begin(),A.end()
 int stringcasecmp(const char *A,const char *AEnd,const char *B,const char *BEnd);
 inline int stringcasecmp(const char *A,const char *AEnd,const char *B) {return stringcasecmp(A,AEnd,B,B+strlen(B));};
 inline int stringcasecmp(string A,const char *B) {return stringcasecmp(A.begin(),A.end(),B,B+strlen(B));};
+inline int stringcasecmp(string A,string B) {return stringcasecmp(A.begin(),A.end(),B.begin(),B.end());};
 
 class URI
 {
@@ -68,9 +78,29 @@ class URI
    operator string();
    inline void operator =(string From) {CopyFrom(From);};
    inline bool empty() {return Access.empty();};
+   static string SiteOnly(string URI);
    
    URI(string Path) {CopyFrom(Path);};
    URI() : Port(0) {};
 };
 
+struct SubstVar
+{
+   const char *Subst;
+   const string *Contents;
+};
+string SubstVar(string Str,const struct SubstVar *Vars);
+string SubstVar(string Str,string Subst,string Contents);
+
+struct RxChoiceList
+{
+   void *UserData;
+   const char *Str;
+   bool Hit;
+};
+unsigned long RegexChoice(RxChoiceList *Rxs,const char **ListBegin,
+		      const char **ListEnd);
+
+#undef APT_FORMAT2
+
 #endif

+ 506 - 0
apt-pkg/deb/debindexfile.cc

@@ -0,0 +1,506 @@
+// -*- mode: cpp; mode: fold -*-
+// Description								/*{{{*/
+// $Id: debindexfile.cc,v 1.2 2001/02/20 07:03:17 jgg Exp $
+/* ######################################################################
+
+   Debian Specific sources.list types and the three sorts of Debian
+   index files.
+   
+   ##################################################################### */
+									/*}}}*/
+// Include Files							/*{{{*/
+#ifdef __GNUG__
+#pragma implementation "apt-pkg/debindexfile.h"
+#endif
+
+#include <apt-pkg/debindexfile.h>
+#include <apt-pkg/debsrcrecords.h>
+#include <apt-pkg/deblistparser.h>
+#include <apt-pkg/debrecords.h>
+#include <apt-pkg/sourcelist.h>
+#include <apt-pkg/configuration.h>
+#include <apt-pkg/progress.h>
+#include <apt-pkg/error.h>
+#include <apt-pkg/strutl.h>
+#include <apt-pkg/acquire-item.h>
+    
+#include <sys/stat.h>
+									/*}}}*/
+
+// SourcesIndex::debSourcesIndex - Constructor				/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+debSourcesIndex::debSourcesIndex(string URI,string Dist,string Section) :
+                                     URI(URI), Dist(Dist), Section(Section)
+{
+}
+									/*}}}*/
+// SourcesIndex::SourceInfo - Short 1 liner describing a source		/*{{{*/
+// ---------------------------------------------------------------------
+/* The result looks like:
+     http://foo/ stable/main src 1.1.1 (dsc) */
+string debSourcesIndex::SourceInfo(pkgSrcRecords::Parser const &Record,
+				   pkgSrcRecords::File const &File) const
+{
+   string Res;
+   Res = ::URI::SiteOnly(URI) + ' ';
+   if (Dist[Dist.size() - 1] == '/')
+   {
+      if (Dist != "/")
+	 Res += Dist;
+   }      
+   else
+      Res += Dist + '/' + Section;
+   
+   Res += " ";
+   Res += Record.Package();
+   Res += " ";
+   Res += Record.Version();
+   if (File.Type.empty() == false)
+      Res += " (" + File.Type + ")";
+   return Res;
+}
+									/*}}}*/
+// SourcesIndex::CreateSrcParser - Get a parser for the source files	/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+pkgSrcRecords::Parser *debSourcesIndex::CreateSrcParser() const
+{
+   string SourcesURI;
+   if (Dist[Dist.size() - 1] == '/')
+      SourcesURI = URI + Dist;
+   else
+      SourcesURI = URI + "dists/" + Dist + '/' + Section +
+      "/source/";
+   
+   SourcesURI += "Sources";
+   SourcesURI = URItoFileName(SourcesURI);
+   return new debSrcRecordParser(_config->FindDir("Dir::State::lists") +
+				 SourcesURI,this);
+}
+									/*}}}*/
+// SourcesIndex::Describe - Give a descriptive path to the index	/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+string debSourcesIndex::Describe() const
+{
+   char S[300];
+   snprintf(S,sizeof(S),"%s (%s)",Info("Packages").c_str(),
+	    IndexFile("Sources").c_str());
+   return S;
+}
+									/*}}}*/
+// SourcesIndex::Info - One liner describing the index URI		/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+string debSourcesIndex::Info(const char *Type) const
+{
+   string Info = ::URI::SiteOnly(URI) + ' ';
+   if (Dist[Dist.size() - 1] == '/')
+   {
+      if (Dist != "/")
+	 Info += Dist;
+   }
+   else
+      Info += Dist + '/' + Section;   
+   Info += " ";
+   Info += Type;
+   return Info;
+}
+									/*}}}*/
+// SourcesIndex::Index* - Return the URI to the index files		/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+inline string debSourcesIndex::IndexFile(const char *Type) const
+{
+   return URItoFileName(IndexURI(Type));
+}
+string debSourcesIndex::IndexURI(const char *Type) const
+{
+   string Res;
+   if (Dist[Dist.size() - 1] == '/')
+   {
+      if (Dist != "/")
+	 Res = URI + Dist;
+      else 
+	 Res = URI;
+   }
+   else
+      Res = URI + "dists/" + Dist + '/' + Section +
+      "/source/";
+   
+   Res += Type;
+   return Res;
+}
+									/*}}}*/
+// SourcesIndex::GetIndexes - Fetch the index files			/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool debSourcesIndex::GetIndexes(pkgAcquire *Owner) const
+{
+   new pkgAcqIndex(Owner,IndexURI("Sources"),Info("Sources"),"Sources");
+   new pkgAcqIndexRel(Owner,IndexURI("Release"),Info("Release"),"Release");
+   return true;
+}
+									/*}}}*/
+// SourcesIndex::Exists - Check if the index is available		/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool debSourcesIndex::Exists() const
+{
+   return FileExists(IndexFile("Sources"));
+}
+									/*}}}*/
+// SourcesIndex::Size - Return the size of the index			/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+unsigned long debSourcesIndex::Size() const
+{
+   struct stat S;
+   if (stat(IndexFile("Sources").c_str(),&S) != 0)
+      return 0;
+   return S.st_size;
+}
+									/*}}}*/
+
+// PackagesIndex::debPackagesIndex - Contructor				/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+debPackagesIndex::debPackagesIndex(string URI,string Dist,string Section) : 
+                  URI(URI), Dist(Dist), Section(Section)
+{
+}
+									/*}}}*/
+// PackagesIndex::ArchiveInfo - Short version of the archive url	/*{{{*/
+// ---------------------------------------------------------------------
+/* This is a shorter version that is designed to be < 60 chars or so */
+string debPackagesIndex::ArchiveInfo(pkgCache::VerIterator Ver) const
+{
+   string Res = ::URI::SiteOnly(URI) + ' ';
+   if (Dist[Dist.size() - 1] == '/')
+   {
+      if (Dist != "/")
+	 Res += Dist;
+   }
+   else
+      Res += Dist + '/' + Section;
+   
+   Res += " ";
+   Res += Ver.ParentPkg().Name();
+   Res += " ";
+   Res += Ver.VerStr();
+   return Res;
+}
+									/*}}}*/
+// PackagesIndex::Describe - Give a descriptive path to the index	/*{{{*/
+// ---------------------------------------------------------------------
+/* This should help the user find the index in the sources.list and
+   in the filesystem for problem solving */
+string debPackagesIndex::Describe() const
+{   
+   char S[300];
+   snprintf(S,sizeof(S),"%s (%s)",Info("Packages").c_str(),
+	    IndexFile("Packages").c_str());
+   return S;
+}
+									/*}}}*/
+// PackagesIndex::Info - One liner describing the index URI		/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+string debPackagesIndex::Info(const char *Type) const 
+{
+   string Info = ::URI::SiteOnly(URI) + ' ';
+   if (Dist[Dist.size() - 1] == '/')
+   {
+      if (Dist != "/")
+	 Info += Dist;
+   }
+   else
+      Info += Dist + '/' + Section;   
+   Info += " ";
+   Info += Type;
+   return Info;
+}
+									/*}}}*/
+// PackagesIndex::Index* - Return the URI to the index files		/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+inline string debPackagesIndex::IndexFile(const char *Type) const
+{
+   return _config->FindDir("Dir::State::lists") + URItoFileName(IndexURI(Type));
+}
+string debPackagesIndex::IndexURI(const char *Type) const
+{
+   string Res;
+   if (Dist[Dist.size() - 1] == '/')
+   {
+      if (Dist != "/")
+	 Res = URI + Dist;
+      else 
+	 Res = URI;
+   }
+   else
+      Res = URI + "dists/" + Dist + '/' + Section +
+      "/binary-" + _config->Find("APT::Architecture") + '/';
+   
+   Res += Type;
+   return Res;
+}
+									/*}}}*/
+// PackagesIndex::GetIndexes - Fetch the index files			/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool debPackagesIndex::GetIndexes(pkgAcquire *Owner) const
+{
+   new pkgAcqIndex(Owner,IndexURI("Packages"),Info("Packages"),"Packages");
+   new pkgAcqIndexRel(Owner,IndexURI("Release"),Info("Release"),"Release");
+   return true;
+}
+									/*}}}*/
+// PackagesIndex::Exists - Check if the index is available		/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool debPackagesIndex::Exists() const
+{
+   return FileExists(IndexFile("Packages"));
+}
+									/*}}}*/
+// PackagesIndex::Size - Return the size of the index			/*{{{*/
+// ---------------------------------------------------------------------
+/* This is really only used for progress reporting. */
+unsigned long debPackagesIndex::Size() const
+{
+   struct stat S;
+   if (stat(IndexFile("Packages").c_str(),&S) != 0)
+      return 0;
+   return S.st_size;
+}
+									/*}}}*/
+// PackagesIndex::Merge - Load the index file into a cache		/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool debPackagesIndex::Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const
+{
+   string PackageFile = IndexFile("Packages");
+   FileFd Pkg(PackageFile,FileFd::ReadOnly);
+   debListParser Parser(&Pkg);
+   if (_error->PendingError() == true)
+      return _error->Error("Problem opening %s",PackageFile.c_str());
+   
+   Prog.SubProgress(0,Info("Packages"));
+   ::URI Tmp(URI);
+   if (Gen.SelectFile(PackageFile,Tmp.Host,*this) == false)
+      return _error->Error("Problem with SelectFile %s",PackageFile.c_str());
+
+   // Store the IMS information
+   pkgCache::PkgFileIterator File = Gen.GetCurFile();
+   struct stat St;
+   if (fstat(Pkg.Fd(),&St) != 0)
+      return _error->Errno("fstat","Failed to stat");
+   File->Size = St.st_size;
+   File->mtime = St.st_mtime;
+   
+   if (Gen.MergeList(Parser) == false)
+      return _error->Error("Problem with MergeList %s",PackageFile.c_str());
+
+   // Check the release file
+   string ReleaseFile = IndexFile("Release");
+   if (FileExists(ReleaseFile) == true)
+   {
+      FileFd Rel(ReleaseFile,FileFd::ReadOnly);
+      if (_error->PendingError() == true)
+	 return false;
+      Parser.LoadReleaseInfo(File,Rel);
+   }
+   
+   return true;
+}
+									/*}}}*/
+// PackagesIndex::FindInCache - Find this index				/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+pkgCache::PkgFileIterator debPackagesIndex::FindInCache(pkgCache &Cache) const
+{
+   string FileName = IndexFile("Packages");
+   pkgCache::PkgFileIterator File = Cache.FileBegin();
+   for (; File.end() == false; File++)
+   {
+      if (FileName != File.FileName())
+	 continue;
+      
+      struct stat St;
+      if (stat(File.FileName(),&St) != 0)
+	 return pkgCache::PkgFileIterator(Cache);
+      if ((unsigned)St.st_size != File->Size || St.st_mtime != File->mtime)
+	 return pkgCache::PkgFileIterator(Cache);
+      return File;
+   }
+   
+   return File;
+}
+									/*}}}*/
+
+// StatusIndex::debStatusIndex - Constructor				/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+debStatusIndex::debStatusIndex(string File) : File(File)
+{
+}
+									/*}}}*/
+// StatusIndex::Size - Return the size of the index			/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+unsigned long debStatusIndex::Size() const
+{
+   struct stat S;
+   if (stat(File.c_str(),&S) != 0)
+      return 0;
+   return S.st_size;
+}
+									/*}}}*/
+// StatusIndex::Merge - Load the index file into a cache		/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool debStatusIndex::Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const
+{
+   FileFd Pkg(File,FileFd::ReadOnly);
+   if (_error->PendingError() == true)
+      return false;
+   debListParser Parser(&Pkg);
+   if (_error->PendingError() == true)
+      return false;
+   
+   Prog.SubProgress(0,File);
+   if (Gen.SelectFile(File,string(),*this,pkgCache::Flag::NotSource) == false)
+      return _error->Error("Problem with SelectFile %s",File.c_str());
+
+   // Store the IMS information
+   pkgCache::PkgFileIterator CFile = Gen.GetCurFile();
+   struct stat St;
+   if (fstat(Pkg.Fd(),&St) != 0)
+      return _error->Errno("fstat","Failed to stat");
+   CFile->Size = St.st_size;
+   CFile->mtime = St.st_mtime;
+   CFile->Archive = Gen.WriteUniqString("now");
+   
+   if (Gen.MergeList(Parser) == false)
+      return _error->Error("Problem with MergeList %s",File.c_str());   
+   return true;
+}
+									/*}}}*/
+// StatusIndex::FindInCache - Find this index				/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+pkgCache::PkgFileIterator debStatusIndex::FindInCache(pkgCache &Cache) const
+{
+   pkgCache::PkgFileIterator File = Cache.FileBegin();
+   for (; File.end() == false; File++)
+   {
+      if (this->File != File.FileName())
+	 continue;
+      
+      struct stat St;
+      if (stat(File.FileName(),&St) != 0)
+	 return pkgCache::PkgFileIterator(Cache);
+      if ((unsigned)St.st_size != File->Size || St.st_mtime != File->mtime)
+	 return pkgCache::PkgFileIterator(Cache);
+      return File;
+   }   
+   return File;
+}
+									/*}}}*/
+// StatusIndex::Exists - Check if the index is available		/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool debStatusIndex::Exists() const
+{
+   // Abort if the file does not exist.
+   return true;
+}
+									/*}}}*/
+
+// Source List types for Debian						/*{{{*/
+class debSLTypeDeb : public pkgSourceList::Type
+{
+   public:
+
+   bool CreateItem(vector<pkgIndexFile *> &List,string URI,
+		   string Dist,string Section) const 
+   {
+      List.push_back(new debPackagesIndex(URI,Dist,Section));
+      return true;
+   };
+
+   debSLTypeDeb()
+   {
+      Name = "deb";
+      Label = "Standard Debian binary tree";
+   }   
+};
+
+class debSLTypeDebSrc : public pkgSourceList::Type
+{
+   public:
+
+   bool CreateItem(vector<pkgIndexFile *> &List,string URI,
+		   string Dist,string Section) const 
+   {
+      List.push_back(new debSourcesIndex(URI,Dist,Section));
+      return true;
+   };  
+   
+   debSLTypeDebSrc()
+   {
+      Name = "deb-src";
+      Label = "Standard Debian source tree";
+   }   
+};
+
+debSLTypeDeb _apt_DebType;
+debSLTypeDebSrc _apt_DebSrcType;
+									/*}}}*/
+// Index File types for Debian						/*{{{*/
+class debIFTypeSrc : public pkgIndexFile::Type
+{
+   public:
+   
+   debIFTypeSrc() {Label = "Debian Source Index";};
+};
+class debIFTypePkg : public pkgIndexFile::Type
+{
+   public:
+   
+   virtual pkgRecords::Parser *CreatePkgParser(pkgCache::PkgFileIterator File) const 
+   {
+      return new debRecordParser(File.FileName(),*File.Cache());
+   };
+   debIFTypePkg() {Label = "Debian Package Index";};
+};
+class debIFTypeStatus : public pkgIndexFile::Type
+{
+   public:
+   
+   virtual pkgRecords::Parser *CreatePkgParser(pkgCache::PkgFileIterator File) const 
+   {
+      return new debRecordParser(File.FileName(),*File.Cache());
+   };
+   debIFTypeStatus() {Label = "Debian dpkg status file";};
+};
+static debIFTypeSrc _apt_Src;
+static debIFTypePkg _apt_Pkg;
+static debIFTypeStatus _apt_Status;
+
+const pkgIndexFile::Type *debSourcesIndex::GetType() const
+{
+   return &_apt_Src;
+}
+const pkgIndexFile::Type *debPackagesIndex::GetType() const
+{
+   return &_apt_Pkg;
+}
+const pkgIndexFile::Type *debStatusIndex::GetType() const
+{
+   return &_apt_Status;
+}
+
+									/*}}}*/

+ 112 - 0
apt-pkg/deb/debindexfile.h

@@ -0,0 +1,112 @@
+// -*- mode: cpp; mode: fold -*-
+// Description								/*{{{*/
+// $Id: debindexfile.h,v 1.2 2001/02/20 07:03:17 jgg Exp $
+/* ######################################################################
+
+   Debian Index Files
+   
+   There are three sorts currently
+   
+   Package files that have File: tags
+   Package files that don't (/var/lib/dpkg/status)
+   Source files
+   
+   ##################################################################### */
+									/*}}}*/
+#ifndef PKGLIB_DEBINDEXFILE_H
+#define PKGLIB_DEBINDEXFILE_H
+
+#ifdef __GNUG__
+#pragma interface "apt-pkg/debindexfile.h"
+#endif
+
+#include <apt-pkg/indexfile.h>
+
+class debStatusIndex : public pkgIndexFile
+{
+   string File;
+   
+   public:
+
+   virtual const Type *GetType() const;
+   
+   // Interface for acquire
+   virtual string Describe() const {return File;};
+   
+   // Interface for the Cache Generator
+   virtual bool Exists() const;
+   virtual bool HasPackages() const {return true;};
+   virtual unsigned long Size() const;
+   virtual bool Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const;
+   virtual pkgCache::PkgFileIterator FindInCache(pkgCache &Cache) const;
+
+   debStatusIndex(string File);
+};
+    
+class debPackagesIndex : public pkgIndexFile
+{
+   string URI;
+   string Dist;
+   string Section;
+   
+   string Info(const char *Type) const;
+   string IndexFile(const char *Type) const;
+   string IndexURI(const char *Type) const;   
+   
+   public:
+   
+   virtual const Type *GetType() const;
+
+   // Stuff for accessing files on remote items
+   virtual string ArchiveInfo(pkgCache::VerIterator Ver) const;
+   virtual string ArchiveURI(string File) const {return URI + File;};
+   
+   // Interface for acquire
+   virtual string Describe() const;   
+   virtual bool GetIndexes(pkgAcquire *Owner) const;
+   
+   // Interface for the Cache Generator
+   virtual bool Exists() const;
+   virtual bool HasPackages() const {return true;};
+   virtual unsigned long Size() const;
+   virtual bool Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const;
+   virtual pkgCache::PkgFileIterator FindInCache(pkgCache &Cache) const;
+   
+   debPackagesIndex(string URI,string Dist,string Section);
+};
+
+class debSourcesIndex : public pkgIndexFile
+{
+   string URI;
+   string Dist;
+   string Section;
+
+   string Info(const char *Type) const;
+   string IndexFile(const char *Type) const;
+   string IndexURI(const char *Type) const;   
+   
+   public:
+
+   virtual const Type *GetType() const;
+
+   // Stuff for accessing files on remote items
+   virtual string SourceInfo(pkgSrcRecords::Parser const &Record,
+			     pkgSrcRecords::File const &File) const;
+   virtual string ArchiveURI(string File) const {return URI + File;};
+   
+   // Interface for acquire
+   virtual string Describe() const;   
+   virtual bool GetIndexes(pkgAcquire *Owner) const;
+
+   // Interface for the record parsers
+   virtual pkgSrcRecords::Parser *CreateSrcParser() const;
+   
+   // Interface for the Cache Generator
+   virtual bool Exists() const;
+   virtual bool HasPackages() const {return false;};
+   virtual unsigned long Size() const;
+   
+   debSourcesIndex(string URI,string Dist,string Section);
+};
+
+#endif

+ 143 - 78
apt-pkg/deb/deblistparser.cc

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: deblistparser.cc,v 1.23 1999/09/30 06:30:34 jgg Exp $
+// $Id: deblistparser.cc,v 1.24 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
    
    Package Cache Generator - Generator for the cache structure.
@@ -19,10 +19,17 @@
 #include <system.h>
 									/*}}}*/
 
+static debListParser::WordList PrioList[] = {{"important",pkgCache::State::Important},
+                       {"required",pkgCache::State::Required},
+                       {"standard",pkgCache::State::Standard},
+                       {"optional",pkgCache::State::Optional},
+	               {"extra",pkgCache::State::Extra},
+                       {}};
+
 // ListParser::debListParser - Constructor				/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-debListParser::debListParser(FileFd &File) : Tags(File)
+debListParser::debListParser(FileFd *File) : Tags(File)
 {
    Arch = _config->Find("APT::architecture");
 }
@@ -80,14 +87,8 @@ bool debListParser::NewVersion(pkgCache::VerIterator Ver)
    const char *Start;
    const char *Stop;
    if (Section.Find("Priority",Start,Stop) == true)
-   {
-      WordList PrioList[] = {{"important",pkgCache::State::Important},
-	                     {"required",pkgCache::State::Required},
-	                     {"standard",pkgCache::State::Standard},
-	                     {"optional",pkgCache::State::Optional},
-	                     {"extra",pkgCache::State::Extra}};
-      if (GrabWord(string(Start,Stop-Start),PrioList,
-		   _count(PrioList),Ver->Priority) == false)
+   {      
+      if (GrabWord(string(Start,Stop-Start),PrioList,Ver->Priority) == false)
 	 Ver->Priority = pkgCache::State::Extra;
    }
 
@@ -104,6 +105,10 @@ bool debListParser::NewVersion(pkgCache::VerIterator Ver)
    if (ParseDepends(Ver,"Replaces",pkgCache::Dep::Replaces) == false)
       return false;
 
+   // Obsolete.
+   if (ParseDepends(Ver,"Optional",pkgCache::Dep::Suggests) == false)
+      return false;
+   
    if (ParseProvides(Ver) == false)
       return false;
    
@@ -205,9 +210,9 @@ bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg,
                           {"install",pkgCache::State::Install},
                           {"hold",pkgCache::State::Hold},
                           {"deinstall",pkgCache::State::DeInstall},
-                          {"purge",pkgCache::State::Purge}};
-   if (GrabWord(string(Start,I-Start),WantList,
-		_count(WantList),Pkg->SelectedState) == false)
+                          {"purge",pkgCache::State::Purge},
+                          {}};
+   if (GrabWord(string(Start,I-Start),WantList,Pkg->SelectedState) == false)
       return _error->Error("Malformed 1st word in the Status line");
 
    // Isloate the next word
@@ -221,9 +226,9 @@ bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg,
    WordList FlagList[] = {{"ok",pkgCache::State::Ok},
                           {"reinstreq",pkgCache::State::ReInstReq},
                           {"hold",pkgCache::State::HoldInst},
-                          {"hold-reinstreq",pkgCache::State::HoldReInstReq}};
-   if (GrabWord(string(Start,I-Start),FlagList,
-		_count(FlagList),Pkg->InstState) == false)
+                          {"hold-reinstreq",pkgCache::State::HoldReInstReq},
+                          {}};
+   if (GrabWord(string(Start,I-Start),FlagList,Pkg->InstState) == false)
       return _error->Error("Malformed 2nd word in the Status line");
 
    // Isloate the last word
@@ -241,9 +246,9 @@ bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg,
                             {"half-installed",pkgCache::State::HalfInstalled},
                             {"config-files",pkgCache::State::ConfigFiles},
                             {"post-inst-failed",pkgCache::State::HalfConfigured},
-                            {"removal-failed",pkgCache::State::HalfInstalled}};
-   if (GrabWord(string(Start,I-Start),StatusList,
-		_count(StatusList),Pkg->CurrentState) == false)
+                            {"removal-failed",pkgCache::State::HalfInstalled},
+                            {}};
+   if (GrabWord(string(Start,I-Start),StatusList,Pkg->CurrentState) == false)
       return _error->Error("Malformed 3rd word in the Status line");
 
    /* A Status line marks the package as indicating the current
@@ -266,9 +271,67 @@ bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg,
 // ---------------------------------------------------------------------
 /* This parses the dependency elements out of a standard string in place,
    bit by bit. */
+const char *debListParser::ConvertRelation(const char *I,unsigned int &Op)
+{
+   // Determine the operator
+   switch (*I)
+   {
+      case '<':
+      I++;
+      if (*I == '=')
+      {
+	 I++;
+	 Op = pkgCache::Dep::LessEq;
+	 break;
+      }
+      
+      if (*I == '<')
+      {
+	 I++;
+	 Op = pkgCache::Dep::Less;
+	 break;
+      }
+      
+      // < is the same as <= and << is really Cs < for some reason
+      Op = pkgCache::Dep::LessEq;
+      break;
+      
+      case '>':
+      I++;
+      if (*I == '=')
+      {
+	 I++;
+	 Op = pkgCache::Dep::GreaterEq;
+	 break;
+      }
+      
+      if (*I == '>')
+      {
+	 I++;
+	 Op = pkgCache::Dep::Greater;
+	 break;
+      }
+      
+      // > is the same as >= and >> is really Cs > for some reason
+      Op = pkgCache::Dep::GreaterEq;
+      break;
+      
+      case '=':
+      Op = pkgCache::Dep::Equals;
+      I++;
+      break;
+      
+      // HACK around bad package definitions
+      default:
+      Op = pkgCache::Dep::Equals;
+      break;
+   }
+   return I;
+}
+
 const char *debListParser::ParseDepends(const char *Start,const char *Stop,
 					string &Package,string &Ver,
-					unsigned int &Op)
+					unsigned int &Op, bool ParseArchFlags)
 {
    // Strip off leading space
    for (;Start != Stop && isspace(*Start) != 0; Start++);
@@ -298,60 +361,7 @@ const char *debListParser::ParseDepends(const char *Start,const char *Stop,
       for (I++; I != Stop && isspace(*I) != 0 ; I++);
       if (I + 3 >= Stop)
 	 return 0;
-      
-      // Determine the operator
-      switch (*I)
-      {
-	 case '<':
-	 I++;
-	 if (*I == '=')
-	 {
-	    I++;
-	    Op = pkgCache::Dep::LessEq;
-	    break;
-	 }
-	 
-	 if (*I == '<')
-	 {
-	    I++;
-	    Op = pkgCache::Dep::Less;
-	    break;
-	 }
-	 
-	 // < is the same as <= and << is really Cs < for some reason
-	 Op = pkgCache::Dep::LessEq;
-	 break;
-	 
-	 case '>':
-	 I++;
-	 if (*I == '=')
-	 {
-	    I++;
-	    Op = pkgCache::Dep::GreaterEq;
-	    break;
-	 }
-	 
-	 if (*I == '>')
-	 {
-	    I++;
-	    Op = pkgCache::Dep::Greater;
-	    break;
-	 }
-	 
-	 // > is the same as >= and >> is really Cs > for some reason
-	 Op = pkgCache::Dep::GreaterEq;
-	 break;
-	 
-	 case '=':
-	 Op = pkgCache::Dep::Equals;
-	 I++;
-	 break;
-	 
-	 // HACK around bad package definitions
-	 default:
-	 Op = pkgCache::Dep::Equals;
-	 break;
-      }
+      I = ConvertRelation(I,Op);
       
       // Skip whitespace
       for (;I != Stop && isspace(*I) != 0; I++);
@@ -375,6 +385,50 @@ const char *debListParser::ParseDepends(const char *Start,const char *Stop,
    
    // Skip whitespace
    for (;I != Stop && isspace(*I) != 0; I++);
+
+   if (ParseArchFlags == true)
+   {
+      string arch = _config->Find("APT::Architecture");
+      
+      // Parse an architecture
+      if (I != Stop && *I == '[')
+      {
+	 // malformed
+         I++;
+         if (I == Stop)
+	    return 0; 
+	 
+         const char *End = I;
+         bool Found = false;
+         while (I != Stop) 
+	 {
+            // look for whitespace or ending ']'
+	    while (End != Stop && !isspace(*End) && *End != ']') 
+	       End++;
+	 
+	    if (End == Stop) 
+	       return 0;
+	    
+	    if (stringcmp(I,End,arch.begin(),arch.end()) == 0)
+	       Found = true;
+	    
+	    if (*End++ == ']') {
+	       I = End;
+	       break;
+	    }
+	    
+	    I = End;
+	    for (;I != Stop && isspace(*I) != 0; I++);
+         }
+	 
+         if (Found == false) 
+	    Package = ""; /* not for this arch */
+      }
+      
+      // Skip whitespace
+      for (;I != Stop && isspace(*I) != 0; I++);
+   }
+
    if (I != Stop && *I == '|')
       Op |= pkgCache::Dep::Or;
    
@@ -453,10 +507,9 @@ bool debListParser::ParseProvides(pkgCache::VerIterator Ver)
 // ListParser::GrabWord - Matches a word and returns			/*{{{*/
 // ---------------------------------------------------------------------
 /* Looks for a word in a list of words - for ParseStatus */
-bool debListParser::GrabWord(string Word,WordList *List,int Count,
-			     unsigned char &Out)
+bool debListParser::GrabWord(string Word,WordList *List,unsigned char &Out)
 {
-   for (int C = 0; C != Count; C++)
+   for (unsigned int C = 0; List[C].Str != 0; C++)
    {
       if (strcasecmp(Word.c_str(),List[C].Str) == 0)
       {
@@ -500,7 +553,7 @@ bool debListParser::Step()
 bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI,
 				    FileFd &File)
 {
-   pkgTagFile Tags(File);
+   pkgTagFile Tags(&File);
    pkgTagSection Section;
    if (Tags.Step(Section) == false)
       return false;
@@ -527,3 +580,15 @@ bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI,
    return !_error->PendingError();
 }
 									/*}}}*/
+// ListParser::GetPrio - Convert the priority from a string		/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+unsigned char debListParser::GetPrio(string Str)
+{
+   unsigned char Out;
+   if (GrabWord(Str,PrioList,Out) == false)
+      Out = pkgCache::State::Extra;
+   
+   return Out;
+}
+									/*}}}*/

+ 22 - 14
apt-pkg/deb/deblistparser.h

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: deblistparser.h,v 1.8 1999/07/26 17:46:08 jgg Exp $
+// $Id: deblistparser.h,v 1.9 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
    
    Debian Package List Parser - This implements the abstract parser 
@@ -8,7 +8,6 @@
    
    ##################################################################### */
 									/*}}}*/
-// Header section: pkglib
 #ifndef PKGLIB_DEBLISTPARSER_H
 #define PKGLIB_DEBLISTPARSER_H
 
@@ -17,29 +16,33 @@
 
 class debListParser : public pkgCacheGenerator::ListParser
 {
-   pkgTagFile Tags;
-   pkgTagSection Section;
-   unsigned long iOffset;
-   string Arch;
-   
+   public:
+
    // Parser Helper
    struct WordList
    {
-      char *Str;
+      const char *Str;
       unsigned char Val;
    };
    
+   private:
+   
+   pkgTagFile Tags;
+   pkgTagSection Section;
+   unsigned long iOffset;
+   string Arch;
+   
    unsigned long UniqFindTagWrite(const char *Tag);
    bool ParseStatus(pkgCache::PkgIterator Pkg,pkgCache::VerIterator Ver);
-   const char *ParseDepends(const char *Start,const char *Stop,
-			    string &Package,string &Ver,unsigned int &Op);
    bool ParseDepends(pkgCache::VerIterator Ver,const char *Tag,
 		     unsigned int Type);
    bool ParseProvides(pkgCache::VerIterator Ver);
-   bool GrabWord(string Word,WordList *List,int Count,unsigned char &Out);
+   static bool GrabWord(string Word,WordList *List,unsigned char &Out);
    
    public:
-   
+
+   static unsigned char GetPrio(string Str);
+      
    // These all operate against the current section
    virtual string Package();
    virtual string Version();
@@ -51,10 +54,15 @@ class debListParser : public pkgCacheGenerator::ListParser
    virtual unsigned long Size() {return Section.size();};
 
    virtual bool Step();
-
+   
    bool LoadReleaseInfo(pkgCache::PkgFileIterator FileI,FileFd &File);
    
-   debListParser(FileFd &File);
+   static const char *ParseDepends(const char *Start,const char *Stop,
+			    string &Package,string &Ver,unsigned int &Op,
+			    bool ParseArchFlags = false);
+   static const char *ConvertRelation(const char *I,unsigned int &Op);
+
+   debListParser(FileFd *File);
 };
 
 #endif

+ 20 - 3
apt-pkg/deb/debrecords.cc

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: debrecords.cc,v 1.8 1999/05/18 05:28:03 jgg Exp $
+// $Id: debrecords.cc,v 1.9 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
    
    Debian Package Records - Parser for debian package records
@@ -18,8 +18,9 @@
 // RecordParser::debRecordParser - Constructor				/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-debRecordParser::debRecordParser(FileFd &File,pkgCache &Cache) : 
-                   Tags(File,Cache.Head().MaxVerFileSize + 20)
+debRecordParser::debRecordParser(string FileName,pkgCache &Cache) : 
+                  File(FileName,FileFd::ReadOnly), 
+                  Tags(&File,Cache.Head().MaxVerFileSize + 200)
 {
 }
 									/*}}}*/
@@ -39,6 +40,14 @@ string debRecordParser::FileName()
    return Section.FindS("Filename");
 }
 									/*}}}*/
+// RecordParser::Name - Return the package name				/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+string debRecordParser::Name()
+{
+   return Section.FindS("Package");
+}
+									/*}}}*/
 // RecordParser::MD5Hash - Return the archive hash			/*{{{*/
 // ---------------------------------------------------------------------
 /* */
@@ -87,3 +96,11 @@ string debRecordParser::SourcePkg()
    return string(Res,0,Pos);
 }
 									/*}}}*/
+// RecordParser::GetRec - Return the whole record			/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+void debRecordParser::GetRec(const char *&Start,const char *&Stop)
+{
+   Section.GetSection(Start,Stop);
+}
+									/*}}}*/

+ 7 - 5
apt-pkg/deb/debrecords.h

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: debrecords.h,v 1.6 1999/04/07 05:30:18 jgg Exp $
+// $Id: debrecords.h,v 1.7 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
    
    Debian Package Records - Parser for debian package records
@@ -11,7 +11,6 @@
    
    ##################################################################### */
 									/*}}}*/
-// Header section: pkglib
 #ifndef PKGLIB_DEBRECORDS_H
 #define PKGLIB_DEBRECORDS_H
 
@@ -24,9 +23,10 @@
 
 class debRecordParser : public pkgRecords::Parser
 {
+   FileFd File;
    pkgTagFile Tags;
    pkgTagSection Section;
-
+   
    protected:
    
    virtual bool Jump(pkgCache::VerFileIterator const &Ver);
@@ -42,9 +42,11 @@ class debRecordParser : public pkgRecords::Parser
    virtual string Maintainer();
    virtual string ShortDesc();
    virtual string LongDesc();
+   virtual string Name();
+
+   virtual void GetRec(const char *&Start,const char *&Stop);
    
-   debRecordParser(FileFd &File,pkgCache &Cache);
+   debRecordParser(string FileName,pkgCache &Cache);
 };
 
-
 #endif

+ 69 - 28
apt-pkg/deb/debsrcrecords.cc

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: debsrcrecords.cc,v 1.3 1999/04/07 05:30:18 jgg Exp $
+// $Id: debsrcrecords.cc,v 1.4 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
    
    Debian Source Package Records - Parser implementation for Debian style
@@ -13,9 +13,11 @@
 #pragma implementation "apt-pkg/debsrcrecords.h"
 #endif 
 
+#include <apt-pkg/deblistparser.h>
 #include <apt-pkg/debsrcrecords.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/strutl.h>
+#include <apt-pkg/configuration.h>
 									/*}}}*/
 
 // SrcRecordParser::Binaries - Return the binaries field		/*{{{*/
@@ -23,43 +25,63 @@
 /* This member parses the binaries field into a pair of class arrays and
    returns a list of strings representing all of the components of the
    binaries field. The returned array need not be freed and will be
-   reused by the next Binaries function call. */
+   reused by the next Binaries function call. This function is commonly
+   used during scanning to find the right package */
 const char **debSrcRecordParser::Binaries()
 {
+   // This should use Start/Stop too, it is supposed to be efficient after all.
    string Bins = Sect.FindS("Binary");
-   char *Buf = Buffer;
-   unsigned int Bin = 0;
-   if (Bins.empty() == true)
+   if (Bins.empty() == true || Bins.length() >= sizeof(Buffer))
       return 0;
    
-   // Strip any leading spaces
-   string::const_iterator Start = Bins.begin();
-   for (; Start != Bins.end() && isspace(*Start) != 0; Start++);
+   strcpy(Buffer,Bins.c_str());
+   if (TokSplitString(',',Buffer,StaticBinList,
+		      sizeof(StaticBinList)/sizeof(StaticBinList[0])) == false)
+      return 0;
+   return (const char **)StaticBinList;
+}
+									/*}}}*/
+// SrcRecordParser::BuildDepends - Return the Build-Depends information	/*{{{*/
+// ---------------------------------------------------------------------
+/* This member parses the build-depends information and returns a list of 
+   package/version records representing the build dependency. The returned 
+   array need not be freed and will be reused by the next call to this 
+   function */
+bool debSrcRecordParser::BuildDepends(vector<pkgSrcRecords::Parser::BuildDepRec> &BuildDeps)
+{
+   unsigned int I;
+   const char *Start, *Stop;
+   BuildDepRec rec;
+   const char *fields[] = {"Build-Depends", 
+                           "Build-Depends-Indep",
+			   "Build-Conflicts",
+			   "Build-Conflicts-Indep"};
+
+   BuildDeps.clear();
 
-   string::const_iterator Pos = Start;
-   while (Pos != Bins.end())
+   for (I = 0; I < 4; I++) 
    {
-      // Skip to the next ','
-      for (; Pos != Bins.end() && *Pos != ','; Pos++);
+      if (Sect.Find(fields[I], Start, Stop) == false)
+         continue;
       
-      // Back remove spaces
-      string::const_iterator End = Pos;
-      for (; End > Start && (End[-1] == ',' || isspace(End[-1]) != 0); End--);
-      
-      // Stash the string
-      memcpy(Buf,Start,End-Start);
-      StaticBinList[Bin] = Buf;
-      Bin++;
-      Buf += End-Start;
-      *Buf++ = 0;
-      
-      // Advance pos
-      for (; Pos != Bins.end() && (*Pos == ',' || isspace(*Pos) != 0); Pos++);
-      Start = Pos;
+      while (1)
+      {
+         Start = debListParser::ParseDepends(Start, Stop, 
+		     rec.Package,rec.Version,rec.Op,true);
+	 
+         if (Start == 0) 
+            return _error->Error("Problem parsing dependency: %s", fields[I]);
+	 rec.Type = I;
+
+	 if (rec.Package != "")
+   	    BuildDeps.push_back(rec);
+	 
+   	 if (Start == Stop) 
+	    break;
+      }	 
    }
    
-   StaticBinList[Bin] = 0;
-   return StaticBinList;
+   return true;
 }
 									/*}}}*/
 // SrcRecordParser::Files - Return a list of files for this source	/*{{{*/
@@ -95,6 +117,25 @@ bool debSrcRecordParser::Files(vector<pkgSrcRecords::File> &List)
       // Parse the size and append the directory
       F.Size = atoi(Size.c_str());
       F.Path = Base + F.Path;
+      
+      // Try to guess what sort of file it is we are getting.
+      string::size_type Pos = F.Path.length()-1;
+      while (1)
+      {
+	 string::size_type Tmp = F.Path.rfind('.',Pos);
+	 if (Tmp == string::npos)
+	    break;
+	 F.Type = string(F.Path,Tmp+1,Pos-Tmp);
+	 
+	 if (F.Type == "gz" || F.Type == "bz2")
+	 {
+	    Pos = Tmp-1;
+	    continue;
+	 }
+	 
+	 break;
+      }
+      
       List.push_back(F);
    }
    

+ 14 - 10
apt-pkg/deb/debsrcrecords.h

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: debsrcrecords.h,v 1.5 1999/10/18 04:15:25 jgg Exp $
+// $Id: debsrcrecords.h,v 1.6 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
    
    Debian Source Package Records - Parser implementation for Debian style
@@ -17,13 +17,15 @@
 
 #include <apt-pkg/srcrecords.h>
 #include <apt-pkg/tagfile.h>
+#include <apt-pkg/fileutl.h>
 
 class debSrcRecordParser : public pkgSrcRecords::Parser
 {
+   FileFd Fd;
    pkgTagFile Tags;
    pkgTagSection Sect;
    char Buffer[10000];
-   const char *StaticBinList[400];
+   char *StaticBinList[400];
    unsigned long iOffset;
    
    public:
@@ -32,11 +34,12 @@ class debSrcRecordParser : public pkgSrcRecords::Parser
    virtual bool Step() {iOffset = Tags.Offset(); return Tags.Step(Sect);};
    virtual bool Jump(unsigned long Off) {iOffset = Off; return Tags.Jump(Sect,Off);};
 
-   virtual string Package() {return Sect.FindS("Package");};
-   virtual string Version() {return Sect.FindS("Version");};
-   virtual string Maintainer() {return Sect.FindS("Maintainer");};
-   virtual string Section() {return Sect.FindS("Section");};
+   virtual string Package() const {return Sect.FindS("Package");};
+   virtual string Version() const {return Sect.FindS("Version");};
+   virtual string Maintainer() const {return Sect.FindS("Maintainer");};
+   virtual string Section() const {return Sect.FindS("Section");};
    virtual const char **Binaries();
+   virtual bool BuildDepends(vector<BuildDepRec> &BuildDeps);
    virtual unsigned long Offset() {return iOffset;};
    virtual string AsStr() 
    {
@@ -45,10 +48,11 @@ class debSrcRecordParser : public pkgSrcRecords::Parser
       return string(Start,Stop);
    };
    virtual bool Files(vector<pkgSrcRecords::File> &F);
-   
-   debSrcRecordParser(FileFd *File,pkgSourceList::const_iterator SrcItem) : 
-                   Parser(File,SrcItem),
-                   Tags(*File,sizeof(Buffer)) {};
+
+   debSrcRecordParser(string File,pkgIndexFile const *Index) :
+                   Parser(Index),      
+                   Fd(File,FileFd::ReadOnly),
+                   Tags(&Fd,sizeof(Buffer)) {};
 };
 
 #endif

+ 197 - 0
apt-pkg/deb/debsystem.cc

@@ -0,0 +1,197 @@
+// -*- mode: cpp; mode: fold -*-
+// Description								/*{{{*/
+// $Id: debsystem.cc,v 1.2 2001/02/20 07:03:17 jgg Exp $
+/* ######################################################################
+
+   System - Abstraction for running on different systems.
+
+   Basic general structure..
+   
+   ##################################################################### */
+									/*}}}*/
+// Include Files							/*{{{*/
+#ifdef __GNUG__
+#pragma implementation "apt-pkg/debsystem.h"
+#endif
+
+#include <apt-pkg/debsystem.h>
+#include <apt-pkg/debversion.h>
+#include <apt-pkg/debindexfile.h>
+#include <apt-pkg/dpkgpm.h>
+#include <apt-pkg/configuration.h>
+#include <apt-pkg/error.h>
+#include <apt-pkg/fileutl.h>
+    
+#include <sys/types.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <errno.h>
+									/*}}}*/
+
+debSystem debSys;
+
+// System::debSystem - Constructor					/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+debSystem::debSystem()
+{
+   LockFD = -1;
+   LockCount = 0;
+   
+   Label = "Debian dpkg interface";
+   VS = &debVS;
+}
+									/*}}}*/
+// System::Lock - Get the lock						/*{{{*/
+// ---------------------------------------------------------------------
+/* This mirrors the operations dpkg does when it starts up. Note the
+   checking of the updates directory. */
+bool debSystem::Lock()
+{
+   // Disable file locking
+   if (_config->FindB("Debug::NoLocking",false) == true || LockCount > 1)
+   {
+      LockCount++;
+      return true;
+   }
+
+   // Create the lockfile
+   string AdminDir = flNotFile(_config->Find("Dir::State::status"));
+   LockFD = GetLock(AdminDir + "lock");
+   if (LockFD == -1)
+   {
+      if (errno == EACCES || errno == EAGAIN)
+	 return _error->Error("Unable to lock the administration directory (%s), "
+			      "is another process using it?",AdminDir.c_str());
+      else
+	 return _error->Error("Unable to lock the administration directory (%s), "
+			      "are you root?",AdminDir.c_str());
+   }
+   
+   // See if we need to abort with a dirty journal
+   if (CheckUpdates() == true)
+   {
+      close(LockFD);
+      LockFD = -1;
+      return _error->Error("dpkg was interrupted, you must manually "
+			   "run 'dpkg --configure -a' to correct the problem. ");
+   }
+
+	 LockCount++;
+      
+   return true;
+}
+									/*}}}*/
+// System::UnLock - Drop a lock						/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool debSystem::UnLock(bool NoErrors)
+{
+   if (LockCount == 0 && NoErrors == true)
+      return false;
+   
+   if (LockCount < 1)
+      return _error->Error("Not locked");
+   if (--LockCount == 0)
+   {
+      close(LockFD);
+      LockCount = 0;
+   }
+   
+   return true;
+}
+									/*}}}*/
+// System::CheckUpdates - Check if the updates dir is dirty		/*{{{*/
+// ---------------------------------------------------------------------
+/* This does a check of the updates directory (dpkg journal) to see if it has 
+   any entries in it. */
+bool debSystem::CheckUpdates()
+{
+   // Check for updates.. (dirty)
+   string File = flNotFile(_config->Find("Dir::State::status")) + "updates/";
+   DIR *DirP = opendir(File.c_str());
+   if (DirP == 0)
+      return false;
+   
+   /* We ignore any files that are not all digits, this skips .,.. and 
+      some tmp files dpkg will leave behind.. */
+   bool Damaged = false;
+   for (struct dirent *Ent = readdir(DirP); Ent != 0; Ent = readdir(DirP))
+   {
+      Damaged = true;
+      for (unsigned int I = 0; Ent->d_name[I] != 0; I++)
+      {
+	 // Check if its not a digit..
+	 if (isdigit(Ent->d_name[I]) == 0)
+	 {
+	    Damaged = false;
+	    break;
+	 }
+      }
+      if (Damaged == true)
+	 break;
+   }
+   closedir(DirP);
+
+   return Damaged;
+}
+									/*}}}*/
+// System::CreatePM - Create the underlying package manager		/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+pkgPackageManager *debSystem::CreatePM(pkgDepCache *Cache) const
+{
+   return new pkgDPkgPM(Cache);
+}
+									/*}}}*/
+// System::Initialize - Setup the configuration space..			/*{{{*/
+// ---------------------------------------------------------------------
+/* These are the Debian specific configuration variables.. */
+bool debSystem::Initialize(Configuration &Cnf)
+{
+   /* These really should be jammed into a generic 'Local Database' engine
+      which is yet to be determined. The functions in pkgcachegen should
+      be the only users of these */
+   Cnf.CndSet("Dir::State::userstatus","status.user"); // Defunct
+   Cnf.CndSet("Dir::State::status","/var/lib/dpkg/status");
+   Cnf.CndSet("Dir::Bin::dpkg","/usr/bin/dpkg");
+   
+   return true;
+}
+									/*}}}*/
+// System::ArchiveSupported - Is a file format supported		/*{{{*/
+// ---------------------------------------------------------------------
+/* The standard name for a deb is 'deb'.. There are no seperate versions
+   of .deb to worry about.. */
+bool debSystem::ArchiveSupported(const char *Type)
+{
+   if (strcmp(Type,"deb") == 0)
+      return true;
+   return false;
+}
+									/*}}}*/
+// System::Score - Determine how 'Debiany' this sys is..		/*{{{*/
+// ---------------------------------------------------------------------
+/* We check some files that are sure tell signs of this being a Debian
+   System.. */
+signed debSystem::Score(Configuration const &Cnf)
+{
+   signed Score = 0;
+   if (FileExists(Cnf.FindFile("Dir::State::status","/var/lib/dpkg/status")) == true)
+       Score += 10;
+   if (FileExists(Cnf.FindFile("Dir::Bin::dpkg","/usr/bin/dpkg")) == true)
+      Score += 10;
+   if (FileExists("/etc/debian_version") == true)
+      Score += 10;
+   return Score;
+}
+									/*}}}*/
+// System::AddStatusFiles - Register the status files			/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool debSystem::AddStatusFiles(vector<pkgIndexFile *> &List)
+{
+   List.push_back(new debStatusIndex(_config->FindFile("Dir::State::status")));
+   return true;
+}
+									/*}}}*/

+ 41 - 0
apt-pkg/deb/debsystem.h

@@ -0,0 +1,41 @@
+// -*- mode: cpp; mode: fold -*-
+// Description								/*{{{*/
+// $Id: debsystem.h,v 1.2 2001/02/20 07:03:17 jgg Exp $
+/* ######################################################################
+
+   System - Debian version of the  System Class
+
+   ##################################################################### */
+									/*}}}*/
+#ifndef PKGLIB_DEBSYSTEM_H
+#define PKGLIB_DEBSYSTEM_H
+
+#ifdef __GNUG__
+#pragma interface "apt-pkg/debsystem.h"
+#endif
+
+#include <apt-pkg/pkgsystem.h>
+    
+class debSystem : public pkgSystem
+{
+   // For locking support
+   int LockFD;
+   unsigned LockCount;
+   bool CheckUpdates();
+   
+   public:
+
+   virtual bool Lock();
+   virtual bool UnLock(bool NoErrors = false);   
+   virtual pkgPackageManager *CreatePM(pkgDepCache *Cache) const;
+   virtual bool Initialize(Configuration &Cnf);
+   virtual bool ArchiveSupported(const char *Type);
+   virtual signed Score(Configuration const &Cnf);
+   virtual bool AddStatusFiles(vector<pkgIndexFile *> &List);
+
+   debSystem();
+};
+
+extern debSystem debSys;
+
+#endif

+ 266 - 0
apt-pkg/deb/debversion.cc

@@ -0,0 +1,266 @@
+// -*- mode: cpp; mode: fold -*-
+// Description								/*{{{*/
+// $Id: debversion.cc,v 1.2 2001/02/20 07:03:17 jgg Exp $
+/* ######################################################################
+
+   Debian Version - Versioning system for Debian
+
+   This implements the standard Debian versioning system.
+   
+   ##################################################################### */
+									/*}}}*/
+// Include Files							/*{{{*/
+#define APT_COMPATIBILITY 986
+#ifdef __GNUG__
+#pragma implementation "apt-pkg/debversion.h"
+#endif
+
+#include <apt-pkg/debversion.h>
+#include <apt-pkg/pkgcache.h>
+
+#include <stdlib.h>
+									/*}}}*/
+
+debVersioningSystem debVS;
+
+// debVS::debVersioningSystem - Constructor				/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+debVersioningSystem::debVersioningSystem()
+{
+   Label = "Standard .deb";
+}
+									/*}}}*/
+// StrToLong - Convert the string between two iterators to a long	/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+static unsigned long StrToLong(const char *begin,const char *end)
+{
+   char S[40];
+   char *I = S;
+   for (; begin != end && I < S + 40;)
+      *I++ = *begin++;
+   *I = 0;
+   return strtoul(S,0,10);
+}
+									/*}}}*/
+// debVS::CmpFragment - Compare versions			        /*{{{*/
+// ---------------------------------------------------------------------
+/* This compares a fragment of the version. Dpkg has a really short 
+   version of this, but it is uh.. interesting to grok. */
+int debVersioningSystem::CmpFragment(const char *A,const char *AEnd, 
+				     const char *B,const char *BEnd)
+{
+   if (A >= AEnd && B >= BEnd)
+      return 0;
+   if (A >= AEnd)
+      return -1;
+   if (B >= BEnd)
+      return 1;
+   
+   /* Iterate over the whole string
+      What this does is to spilt the whole string into groups of 
+      numeric and non numeric portions. For instance:
+         a67bhgs89
+      Has 4 portions 'a', '67', 'bhgs', '89'. A more normal:
+         2.7.2-linux-1
+      Has '2', '.', '7', '.' ,'-linux-','1' */
+   const char *lhs = A;
+   const char *rhs = B;
+   while (lhs != AEnd && rhs != BEnd)
+   {
+      // Starting points
+      const char *Slhs = lhs;
+      const char *Srhs = rhs;
+      
+      // Compute ending points were we have passed over the portion
+      bool Digit = (isdigit(*lhs) > 0?true:false);
+      for (;lhs != AEnd && (isdigit(*lhs) > 0?true:false) == Digit; lhs++);
+      for (;rhs != BEnd && (isdigit(*rhs) > 0?true:false) == Digit; rhs++);
+      
+      if (Digit == true)
+      {
+	 // If the lhs has a digit and the rhs does not then <
+	 if (rhs - Srhs == 0)
+	    return -1;
+	 
+	 // Generate integers from the strings.
+	 unsigned long Ilhs = StrToLong(Slhs,lhs);
+	 unsigned long Irhs = StrToLong(Srhs,rhs);
+	 if (Ilhs != Irhs)
+	 {
+	    if (Ilhs > Irhs)
+	       return 1;
+	    return -1;
+	 }
+      }
+      else
+      {
+	 // They are equal length so do a straight text compare
+	 for (;Slhs != lhs && Srhs != rhs; Slhs++, Srhs++)
+	 {
+	    if (*Slhs != *Srhs)
+	    {
+	       /* We need to compare non alpha chars as higher than alpha
+	          chars (a < !) */
+	       int lc = *Slhs;
+	       int rc = *Srhs;
+	       if (isalpha(lc) == 0) lc += 256;
+	       if (isalpha(rc) == 0) rc += 256;
+	       if (lc > rc)
+		  return 1;
+	       return -1;
+	    }
+	 }
+
+	 // If the lhs is shorter than the right it is 'less'
+	 if (lhs - Slhs < rhs - Srhs)
+	    return -1;
+
+	 // If the lhs is longer than the right it is 'more'
+	 if (lhs - Slhs > rhs - Srhs)
+	    return 1;		 
+      }      
+   }
+
+   // The strings must be equal
+   if (lhs == AEnd && rhs == BEnd)
+      return 0;
+
+   // lhs is shorter
+   if (lhs == AEnd)
+      return -1;
+
+   // rhs is shorter
+   if (rhs == BEnd)
+      return 1;
+       
+   // Shouldnt happen
+   return 1;
+}
+									/*}}}*/
+// debVS::CmpVersion - Comparison for versions				/*{{{*/
+// ---------------------------------------------------------------------
+/* This fragments the version into E:V-R triples and compares each 
+   portion separately. */
+int debVersioningSystem::DoCmpVersion(const char *A,const char *AEnd,
+				      const char *B,const char *BEnd)
+{
+   // Strip off the epoch and compare it 
+   const char *lhs = A;
+   const char *rhs = B;
+   for (;lhs != AEnd && *lhs != ':'; lhs++);
+   for (;rhs != BEnd && *rhs != ':'; rhs++);
+   if (lhs == AEnd)
+      lhs = A;
+   if (rhs == BEnd)
+      rhs = B;
+   
+   // Compare the epoch
+   int Res = CmpFragment(A,lhs,B,rhs);
+   if (Res != 0)
+      return Res;
+
+   // Skip the :
+   if (lhs != A)
+      lhs++;
+   if (rhs != B)
+      rhs++;
+   
+   // Find the last - 
+   const char *dlhs = AEnd-1;
+   const char *drhs = BEnd-1;
+   for (;dlhs > lhs && *dlhs != '-'; dlhs--);
+   for (;drhs > rhs && *drhs != '-'; drhs--);
+
+   if (dlhs == lhs)
+      dlhs = AEnd;
+   if (drhs == rhs)
+      drhs = BEnd;
+   
+   // Compare the main version
+   Res = CmpFragment(lhs,dlhs,rhs,drhs);
+   if (Res != 0)
+      return Res;
+   
+   // Skip the -
+   if (dlhs != lhs)
+      dlhs++;
+   if (drhs != rhs)
+      drhs++;
+   
+   return CmpFragment(dlhs,AEnd,drhs,BEnd);
+}
+									/*}}}*/
+// debVS::CheckDep - Check a single dependency				/*{{{*/
+// ---------------------------------------------------------------------
+/* This simply preforms the version comparison and switch based on 
+   operator. If DepVer is 0 then we are comparing against a provides
+   with no version. */
+bool debVersioningSystem::CheckDep(const char *PkgVer,
+				   int Op,const char *DepVer)
+{
+   if (DepVer == 0 || DepVer[0] == 0)
+      return true;
+   if (PkgVer == 0 || PkgVer[0] == 0)
+      return false;
+   
+   // Perform the actual comparision.
+   int Res = CmpVersion(PkgVer,DepVer);
+   switch (Op & 0x0F)
+   {
+      case pkgCache::Dep::LessEq:
+      if (Res <= 0)
+	 return true;
+      break;
+      
+      case pkgCache::Dep::GreaterEq:
+      if (Res >= 0)
+	 return true;
+      break;
+      
+      case pkgCache::Dep::Less:
+      if (Res < 0)
+	 return true;
+      break;
+      
+      case pkgCache::Dep::Greater:
+      if (Res > 0)
+	 return true;
+      break;
+      
+      case pkgCache::Dep::Equals:
+      if (Res == 0)
+	 return true;
+      break;
+      
+      case pkgCache::Dep::NotEquals:
+      if (Res != 0)
+	 return true;
+      break;
+   }
+
+   return false;
+}
+									/*}}}*/
+// debVS::UpstreamVersion - Return the upstream version string		/*{{{*/
+// ---------------------------------------------------------------------
+/* This strips all the debian specific information from the version number */
+string debVersioningSystem::UpstreamVersion(const char *Ver)
+{
+   // Strip off the bit before the first colon
+   const char *I = Ver;
+   for (; *I != 0 && *I != ':'; I++);
+   if (*I == ':')
+      Ver = I + 1;
+   
+   // Chop off the trailing -
+   I = Ver;
+   unsigned Last = strlen(Ver);
+   for (; *I != 0; I++)
+      if (*I == '-')
+	 Last = I - Ver;
+   
+   return string(Ver,Last);
+}
+									/*}}}*/

+ 72 - 0
apt-pkg/deb/debversion.h

@@ -0,0 +1,72 @@
+// -*- mode: cpp; mode: fold -*-
+// Description								/*{{{*/
+// $Id: debversion.h,v 1.2 2001/02/20 07:03:17 jgg Exp $
+/* ######################################################################
+
+   Debian Version - Versioning system for Debian
+
+   This implements the standard Debian versioning system.
+   
+   ##################################################################### */
+									/*}}}*/
+#ifndef PKGLIB_DEBVERSION_H
+#define PKGLIB_DEBVERSION_H
+
+#ifdef __GNUG__
+#pragma interface "apt-pkg/debversion.h"
+#endif 
+
+#include <apt-pkg/version.h>
+    
+class debVersioningSystem : public pkgVersioningSystem
+{  
+   static int CmpFragment(const char *A, const char *AEnd, const char *B,
+			  const char *BEnd);
+   
+   public:
+   
+   // Compare versions..
+   virtual int DoCmpVersion(const char *A,const char *Aend,
+			  const char *B,const char *Bend);
+   virtual bool CheckDep(const char *PkgVer,int Op,const char *DepVer);
+   virtual int DoCmpReleaseVer(const char *A,const char *Aend,
+			     const char *B,const char *Bend)
+   {
+      return DoCmpVersion(A,Aend,B,Bend);
+   }   
+   virtual string UpstreamVersion(const char *A);
+
+   debVersioningSystem();
+};
+
+extern debVersioningSystem debVS;
+
+#ifdef APT_COMPATIBILITY
+#if APT_COMPATIBILITY != 986
+#warning "Using APT_COMPATIBILITY"
+#endif
+
+inline int pkgVersionCompare(const char *A, const char *B)
+{
+   return debVS.CmpVersion(A,B);
+}
+inline int pkgVersionCompare(const char *A, const char *AEnd, 
+			     const char *B, const char *BEnd)
+{
+   return debVS.DoCmpVersion(A,AEnd,B,BEnd);
+}
+inline int pkgVersionCompare(string A,string B)
+{
+   return debVS.CmpVersion(A,B);
+}
+inline bool pkgCheckDep(const char *DepVer,const char *PkgVer,int Op)
+{
+   return debVS.CheckDep(PkgVer,Op,DepVer);
+}
+inline string pkgBaseVersion(const char *Ver)
+{
+   return debVS.UpstreamVersion(Ver);
+}
+#endif
+
+#endif

+ 0 - 119
apt-pkg/deb/dpkginit.cc

@@ -1,119 +0,0 @@
-// -*- mode: cpp; mode: fold -*-
-// Description								/*{{{*/
-// $Id: dpkginit.cc,v 1.5 1999/08/03 05:21:19 jgg Exp $
-/* ######################################################################
-
-   DPKG init - Initialize the dpkg stuff
-
-   This class provides the locking mechanism used by dpkg for its 
-   database area. It does the proper consistency checks and acquires the
-   correct kind of lock.
-   
-   ##################################################################### */
-									/*}}}*/
-// Includes								/*{{{*/
-#ifdef __GNUG__
-#pragma implementation "apt-pkg/dpkginit.h"
-#endif
-#include <apt-pkg/dpkginit.h>
-#include <apt-pkg/error.h>
-#include <apt-pkg/configuration.h>
-#include <apt-pkg/fileutl.h>
-
-#include <sys/types.h>
-#include <unistd.h>
-#include <dirent.h>
-									/*}}}*/
-
-// DpkgLock::pkgDpkgLock - Constructor					/*{{{*/
-// ---------------------------------------------------------------------
-/* */
-pkgDpkgLock::pkgDpkgLock(bool WithUpdates)
-{
-   LockFD = -1;
-   GetLock(WithUpdates);
-}
-									/*}}}*/
-// DpkgLock::~pkgDpkgLock - Destructor					/*{{{*/
-// ---------------------------------------------------------------------
-/* */
-pkgDpkgLock::~pkgDpkgLock()
-{
-   Close();
-}
-									/*}}}*/
-// DpkgLock::GetLock - Get the lock					/*{{{*/
-// ---------------------------------------------------------------------
-/* This mirrors the operations dpkg does when it starts up. Note the
-   checking of the updates directory. */
-bool pkgDpkgLock::GetLock(bool WithUpdates)
-{
-   // Disable file locking
-   if (_config->FindB("Debug::NoLocking",false) == true)
-      return true;
-   
-   Close();
-   
-   // Create the lockfile
-   string AdminDir = flNotFile(_config->Find("Dir::State::status"));
-   LockFD = ::GetLock(AdminDir + "lock");
-   if (LockFD == -1)
-      return _error->Error("Unable to lock the administration directory, "
-			   "are you root?");
-
-   // See if we need to abort with a dirty journal
-   if (WithUpdates == true && CheckUpdates() == true)
-   {
-      Close();
-      return _error->Error("dpkg was interrupted, you must manually "
-			   "run 'dpkg --configure -a' to correct the problem. ");
-   }
-      
-   return true;
-}
-									/*}}}*/
-// DpkgLock::Close - Close the lock					/*{{{*/
-// ---------------------------------------------------------------------
-/* */
-void pkgDpkgLock::Close()
-{
-   close(LockFD);
-   LockFD = -1;
-}
-									/*}}}*/
-// DpkgLock::CheckUpdates - Check if the updates dir is dirty		/*{{{*/
-// ---------------------------------------------------------------------
-/* This does a check of the updates directory to see if it has any entries
-   in it. */
-bool pkgDpkgLock::CheckUpdates()
-{
-   // Check for updates.. (dirty)
-   string File = flNotFile(_config->Find("Dir::State::status")) + "updates/";
-   DIR *DirP = opendir(File.c_str());
-   if (DirP == 0)
-      return false;
-   
-   /* We ignore any files that are not all digits, this skips .,.. and 
-      some tmp files dpkg will leave behind.. */
-   bool Damaged = false;
-   for (struct dirent *Ent = readdir(DirP); Ent != 0; Ent = readdir(DirP))
-   {
-      Damaged = true;
-      for (unsigned int I = 0; Ent->d_name[I] != 0; I++)
-      {
-	 // Check if its not a digit..
-	 if (isdigit(Ent->d_name[I]) == 0)
-	 {
-	    Damaged = false;
-	    break;
-	 }
-      }
-      if (Damaged == true)
-	 break;
-   }
-   closedir(DirP);
-
-   return Damaged;
-}
-									/*}}}*/
-   

+ 0 - 34
apt-pkg/deb/dpkginit.h

@@ -1,34 +0,0 @@
-// -*- mode: cpp; mode: fold -*-
-// Description								/*{{{*/
-// $Id: dpkginit.h,v 1.2 1999/07/26 17:46:08 jgg Exp $
-/* ######################################################################
-
-   DPKG init - Initialize the dpkg stuff
-   
-   This basically gets a lock in /var/lib/dpkg and checks the updates
-   directory
-   
-   ##################################################################### */
-									/*}}}*/
-#ifndef PKGLIB_DPKGINIT_H
-#define PKGLIB_DPKGINIT_H
-
-#ifdef __GNUG__
-#pragma interface "apt-pkg/dpkginit.h"
-#endif
-
-class pkgDpkgLock
-{
-   int LockFD;
-      
-   public:
-   
-   bool CheckUpdates();
-   bool GetLock(bool WithUpdates);
-   void Close();
-
-   pkgDpkgLock(bool WithUpdates = true);
-   ~pkgDpkgLock();
-};
-
-#endif

+ 136 - 26
apt-pkg/deb/dpkgpm.cc

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: dpkgpm.cc,v 1.17 2000/05/13 01:52:38 jgg Exp $
+// $Id: dpkgpm.cc,v 1.18 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
 
    DPKG Package Manager - Provide an interface to dpkg
@@ -14,7 +14,9 @@
 #include <apt-pkg/dpkgpm.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/configuration.h>
-
+#include <apt-pkg/depcache.h>
+#include <apt-pkg/strutl.h>
+    
 #include <unistd.h>
 #include <stdlib.h>
 #include <fcntl.h>
@@ -28,7 +30,7 @@
 // DPkgPM::pkgDPkgPM - Constructor					/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-pkgDPkgPM::pkgDPkgPM(pkgDepCache &Cache) : pkgPackageManager(Cache)
+pkgDPkgPM::pkgDPkgPM(pkgDepCache *Cache) : pkgPackageManager(Cache)
 {
 }
 									/*}}}*/
@@ -141,6 +143,90 @@ bool pkgDPkgPM::RunScripts(const char *Cnf)
 }
 
                                                                         /*}}}*/
+// DPkgPM::SendV2Pkgs - Send version 2 package info			/*{{{*/
+// ---------------------------------------------------------------------
+/* This is part of the helper script communication interface, it sends
+   very complete information down to the other end of the pipe.*/
+bool pkgDPkgPM::SendV2Pkgs(FILE *F)
+{
+   fprintf(F,"VERSION 2\n");
+   
+   /* Write out all of the configuration directives by walking the 
+      configuration tree */
+   const Configuration::Item *Top = _config->Tree(0);
+   for (; Top != 0;)
+   {
+      if (Top->Value.empty() == false)
+      {
+	 fprintf(F,"%s=%s\n",
+		 QuoteString(Top->FullTag(),"=\"\n").c_str(),
+		 QuoteString(Top->Value,"\n").c_str());
+      }
+
+      if (Top->Child != 0)
+      {
+	 Top = Top->Child;
+	 continue;
+      }
+      
+      while (Top != 0 && Top->Next == 0)
+	 Top = Top->Parent;
+      if (Top != 0)
+	 Top = Top->Next;
+   }   
+   fprintf(F,"\n");
+ 
+   // Write out the package actions in order.
+   for (vector<Item>::iterator I = List.begin(); I != List.end(); I++)
+   {
+      pkgDepCache::StateCache &S = Cache[I->Pkg];
+      
+      fprintf(F,"%s ",I->Pkg.Name());
+      // Current version
+      if (I->Pkg->CurrentVer == 0)
+	 fprintf(F,"- ");
+      else
+	 fprintf(F,"%s ",I->Pkg.CurrentVer().VerStr());
+      
+      // Show the compare operator
+      // Target version
+      if (S.InstallVer != 0)
+      {
+	 int Comp = 2;
+	 if (I->Pkg->CurrentVer != 0)
+	    Comp = S.InstVerIter(Cache).CompareVer(I->Pkg.CurrentVer());
+	 if (Comp < 0)
+	    fprintf(F,"> ");
+	 if (Comp == 0)
+	    fprintf(F,"= ");
+	 if (Comp > 0)
+	    fprintf(F,"< ");
+	 fprintf(F,"%s ",S.InstVerIter(Cache).VerStr());
+      }
+      else
+	 fprintf(F,"> - ");
+      
+      // Show the filename/operation
+      if (I->Op == Item::Install)
+      {
+	 // No errors here..
+	 if (I->File[0] != '/')
+	    fprintf(F,"**ERROR**\n");
+	 else
+	    fprintf(F,"%s\n",I->File.c_str());
+      }      
+      if (I->Op == Item::Configure)
+	 fprintf(F,"**CONFIGURE**\n");
+      if (I->Op == Item::Remove ||
+	  I->Op == Item::Purge)
+	 fprintf(F,"**REMOVE**\n");
+      
+      if (ferror(F) != 0)
+	 return false;
+   }
+   return true;
+}
+									/*}}}*/
 // DPkgPM::RunScriptsWithPkgs - Run scripts with package names on stdin /*{{{*/
 // ---------------------------------------------------------------------
 /* This looks for a list of scripts to run from the configuration file
@@ -158,7 +244,18 @@ bool pkgDPkgPM::RunScriptsWithPkgs(const char *Cnf)
    {
       if (Opts->Value.empty() == true)
          continue;
-		
+
+      // Determine the protocol version
+      string OptSec = Opts->Value;
+      string::size_type Pos;
+      if ((Pos = OptSec.find(' ')) == string::npos || Pos == 0)
+	 Pos = OptSec.length();
+      else
+	 Pos--;
+      OptSec = "DPkg::Tools::Options::" + string(Opts->Value.c_str(),Pos);
+      
+      unsigned int Version = _config->FindI(OptSec+"::Version",1);
+      
       // Create the pipes
       int Pipes[2];
       if (pipe(Pipes) != 0)
@@ -185,31 +282,44 @@ bool pkgDPkgPM::RunScriptsWithPkgs(const char *Cnf)
 	 _exit(100);
       }
       close(Pipes[0]);
-      FileFd Fd(Pipes[1]);
-
+      FILE *F = fdopen(Pipes[1],"w");
+      if (F == 0)
+	 return _error->Errno("fdopen","Faild to open new FD");
+      
       // Feed it the filenames.
-      for (vector<Item>::iterator I = List.begin(); I != List.end(); I++)
+      bool Die = false;
+      if (Version <= 1)
       {
-	 // Only deal with packages to be installed from .deb
-	 if (I->Op != Item::Install)
-	    continue;
-
-	 // No errors here..
-	 if (I->File[0] != '/')
-	    continue;
-	 
-	 /* Feed the filename of each package that is pending install
-	    into the pipe. */
-	 if (Fd.Write(I->File.begin(),I->File.length()) == false || 
-	     Fd.Write("\n",1) == false)
+	 for (vector<Item>::iterator I = List.begin(); I != List.end(); I++)
 	 {
-	    kill(Process,SIGINT);	    
-	    Fd.Close();   
-	    ExecWait(Process,Opts->Value.c_str(),true);
-	    return _error->Error("Failure running script %s",Opts->Value.c_str());
+	    // Only deal with packages to be installed from .deb
+	    if (I->Op != Item::Install)
+	       continue;
+
+	    // No errors here..
+	    if (I->File[0] != '/')
+	       continue;
+	    
+	    /* Feed the filename of each package that is pending install
+	       into the pipe. */
+	    fprintf(F,"%s\n",I->File.c_str());
+	    if (ferror(F) != 0)
+	    {
+	       Die = true;
+	       break;
+	    }
 	 }
       }
-      Fd.Close();
+      else
+	 Die = !SendV2Pkgs(F);
+
+      fclose(F);
+      if (Die == true)
+      {
+	 kill(Process,SIGINT);
+	 ExecWait(Process,Opts->Value.c_str(),true);
+	 return _error->Error("Failure running script %s",Opts->Value.c_str());
+      }
       
       // Clean up the sub process
       if (ExecWait(Process,Opts->Value.c_str()) == false)
@@ -384,8 +494,8 @@ bool pkgDPkgPM::Go()
       {
 	 RunScripts("DPkg::Post-Invoke");
 	 if (WIFSIGNALED(Status) != 0 && WTERMSIG(Status) == SIGSEGV)
-	    return _error->Error("Sub-process %s recieved a segmentation fault.",Args[0]);
-	    
+	    return _error->Error("Sub-process %s received a segmentation fault.",Args[0]);
+
 	 if (WIFEXITED(Status) != 0)
 	    return _error->Error("Sub-process %s returned an error code (%u)",Args[0],WEXITSTATUS(Status));
 	 

+ 5 - 3
apt-pkg/deb/dpkgpm.h

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: dpkgpm.h,v 1.6 1999/07/30 06:15:14 jgg Exp $
+// $Id: dpkgpm.h,v 1.7 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
 
    DPKG Package Manager - Provide an interface to dpkg
@@ -16,6 +16,7 @@
 
 #include <apt-pkg/packagemanager.h>
 #include <vector>
+#include <stdio.h>
 
 class pkgDPkgPM : public pkgPackageManager
 {
@@ -26,7 +27,7 @@ class pkgDPkgPM : public pkgPackageManager
       enum Ops {Install, Configure, Remove, Purge} Op;
       string File;
       PkgIterator Pkg;
-      Item(Ops Op,PkgIterator Pkg,string File = "") : Op(Op), 
+      Item(Ops Op,PkgIterator Pkg,string File = "") : Op(Op),
             File(File), Pkg(Pkg) {};
       Item() {};
       
@@ -36,6 +37,7 @@ class pkgDPkgPM : public pkgPackageManager
    // Helpers
    bool RunScripts(const char *Cnf);
    bool RunScriptsWithPkgs(const char *Cnf);
+   bool SendV2Pkgs(FILE *F);
    
    // The Actuall installation implementation
    virtual bool Install(PkgIterator Pkg,string File);
@@ -46,7 +48,7 @@ class pkgDPkgPM : public pkgPackageManager
    
    public:
 
-   pkgDPkgPM(pkgDepCache &Cache);
+   pkgDPkgPM(pkgDepCache *Cache);
    virtual ~pkgDPkgPM();
 };
 

+ 164 - 91
apt-pkg/depcache.cc

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: depcache.cc,v 1.22 2000/05/31 02:49:37 jgg Exp $
+// $Id: depcache.cc,v 1.23 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
 
    Dependency Cache - Caches Dependency information.
@@ -12,25 +12,24 @@
 #pragma implementation "apt-pkg/depcache.h"
 #endif
 #include <apt-pkg/depcache.h>
-
 #include <apt-pkg/version.h>
 #include <apt-pkg/error.h>
+#include <apt-pkg/sptr.h>
+#include <apt-pkg/algorithms.h>
+    
+#include <apti18n.h>    
 									/*}}}*/
 
 // DepCache::pkgDepCache - Constructors					/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-pkgDepCache::pkgDepCache(MMap &Map,OpProgress &Prog) :
-             pkgCache(Map), PkgState(0), DepState(0)
+pkgDepCache::pkgDepCache(pkgCache *pCache,Policy *Plcy) :
+                Cache(pCache), PkgState(0), DepState(0)
 {
-   if (_error->PendingError() == false)
-      Init(&Prog);
-}
-pkgDepCache::pkgDepCache(MMap &Map) :
-             pkgCache(Map), PkgState(0), DepState(0)
-{
-   if (_error->PendingError() == false)
-      Init(0);
+   delLocalPolicy = 0;
+   LocalPolicy = Plcy;
+   if (LocalPolicy == 0)
+      delLocalPolicy = LocalPolicy = new Policy;
 }
 									/*}}}*/
 // DepCache::~pkgDepCache - Destructor					/*{{{*/
@@ -40,6 +39,7 @@ pkgDepCache::~pkgDepCache()
 {
    delete [] PkgState;
    delete [] DepState;
+   delete delLocalPolicy;
 }
 									/*}}}*/
 // DepCache::Init - Generate the initial extra structures.		/*{{{*/
@@ -53,12 +53,12 @@ bool pkgDepCache::Init(OpProgress *Prog)
    DepState = new unsigned char[Head().DependsCount];
    memset(PkgState,0,sizeof(*PkgState)*Head().PackageCount);
    memset(DepState,0,sizeof(*DepState)*Head().DependsCount); 
-   
+
    if (Prog != 0)
    {
       Prog->OverallProgress(0,2*Head().PackageCount,Head().PackageCount,
-			    "Building Dependency Tree");
-      Prog->SubProgress(Head().PackageCount,"Candidate Versions");
+			    _("Building Dependency Tree"));
+      Prog->SubProgress(Head().PackageCount,_("Candidate Versions"));
    }
    
    /* Set the current state of everything. In this state all of the
@@ -86,8 +86,8 @@ bool pkgDepCache::Init(OpProgress *Prog)
       
       Prog->OverallProgress(Head().PackageCount,2*Head().PackageCount,
 			    Head().PackageCount,
-			    "Building Dependency Tree");
-      Prog->SubProgress(Head().PackageCount,"Dependency Generation");
+			    _("Building Dependency Tree"));
+      Prog->SubProgress(Head().PackageCount,_("Dependency Generation"));
    }
    
    Update(Prog);
@@ -95,29 +95,6 @@ bool pkgDepCache::Init(OpProgress *Prog)
    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,
-						      bool AllowCurrent)
-{
-   // Try to use an explicit target
-   if (Pkg->TargetVer == 0 || 
-       (AllowCurrent == false && Pkg.TargetVer() == Pkg.CurrentVer()))
-      return pkgCache::GetCandidateVer(Pkg,AllowCurrent);
-   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			/*{{{*/
 // ---------------------------------------------------------------------
@@ -132,28 +109,30 @@ bool pkgDepCache::CheckDep(DepIterator Dep,int Type,PkgIterator &Res)
    /* 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)
+   if (Dep.TargetPkg() != Dep.ParentPkg() || 
+       (Dep->Type != Dep::Conflicts && Dep->Type != Dep::Obsoletes))
    {
       PkgIterator Pkg = Dep.TargetPkg();
       // Check the base package
       if (Type == NowVersion && Pkg->CurrentVer != 0)
-	 if (pkgCheckDep(Dep.TargetVer(),
-			 Pkg.CurrentVer().VerStr(),Dep->CompareOp) == true)
+	 if (VS().CheckDep(Pkg.CurrentVer().VerStr(),Dep->CompareOp,
+				 Dep.TargetVer()) == true)
 	    return true;
       
       if (Type == InstallVersion && PkgState[Pkg->ID].InstallVer != 0)
-	 if (pkgCheckDep(Dep.TargetVer(),
-			 PkgState[Pkg->ID].InstVerIter(*this).VerStr(),
-			 Dep->CompareOp) == true)
+	 if (VS().CheckDep(PkgState[Pkg->ID].InstVerIter(*this).VerStr(),
+				 Dep->CompareOp,Dep.TargetVer()) == true)
 	    return true;
       
       if (Type == CandidateVersion && PkgState[Pkg->ID].CandidateVer != 0)
-	 if (pkgCheckDep(Dep.TargetVer(),
-			 PkgState[Pkg->ID].CandidateVerIter(*this).VerStr(),
-			 Dep->CompareOp) == true)
+	 if (VS().CheckDep(PkgState[Pkg->ID].CandidateVerIter(*this).VerStr(),
+				 Dep->CompareOp,Dep.TargetVer()) == true)
 	    return true;
    }
    
+   if (Dep->Type == Dep::Obsoletes)
+      return false;
+   
    // Check the providing packages
    PrvIterator P = Dep.TargetPkg().ProvidesList();
    PkgIterator Pkg = Dep.ParentPkg();
@@ -186,7 +165,7 @@ bool pkgDepCache::CheckDep(DepIterator Dep,int Type,PkgIterator &Res)
       }
       
       // Compare the versions.
-      if (pkgCheckDep(Dep.TargetVer(),P.ProvideVersion(),Dep->CompareOp) == true)
+      if (VS().CheckDep(P.ProvideVersion(),Dep->CompareOp,Dep.TargetVer()) == true)
       {
 	 Res = P.OwnerPkg();
 	 return true;
@@ -199,7 +178,7 @@ bool pkgDepCache::CheckDep(DepIterator Dep,int Type,PkgIterator &Res)
 // 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)
+void pkgDepCache::AddSizes(const PkgIterator &Pkg,signed long Mult)
 {
    StateCache &P = PkgState[Pkg->ID];
    
@@ -210,8 +189,8 @@ void pkgDepCache::AddSizes(const PkgIterator &Pkg,long Mult)
    // Compute the size data
    if (P.NewInstall() == true)
    {
-      iUsrSize += Mult*P.InstVerIter(*this)->InstalledSize;
-      iDownloadSize += Mult*P.InstVerIter(*this)->Size;
+      iUsrSize += (signed)(Mult*P.InstVerIter(*this)->InstalledSize);
+      iDownloadSize += (signed)(Mult*P.InstVerIter(*this)->Size);
       return;
    }
    
@@ -220,9 +199,9 @@ void pkgDepCache::AddSizes(const PkgIterator &Pkg,long Mult)
        (P.InstallVer != (Version *)Pkg.CurrentVer() || 
 	(P.iFlags & ReInstall) == ReInstall) && P.InstallVer != 0)
    {
-      iUsrSize += Mult*((signed)P.InstVerIter(*this)->InstalledSize - 
-			(signed)Pkg.CurrentVer()->InstalledSize);
-      iDownloadSize += Mult*P.InstVerIter(*this)->Size;
+      iUsrSize += (signed)(Mult*((signed)P.InstVerIter(*this)->InstalledSize - 
+			(signed)Pkg.CurrentVer()->InstalledSize));
+      iDownloadSize += (signed)(Mult*P.InstVerIter(*this)->Size);
       return;
    }
    
@@ -230,14 +209,14 @@ void pkgDepCache::AddSizes(const PkgIterator &Pkg,long Mult)
    if (Pkg.State() == pkgCache::PkgIterator::NeedsUnpack &&
        P.Delete() == false)
    {
-      iDownloadSize += Mult*P.InstVerIter(*this)->Size;
+      iDownloadSize += (signed)(Mult*P.InstVerIter(*this)->Size);
       return;
    }
    
    // Removing
    if (Pkg->CurrentVer != 0 && P.InstallVer == 0)
    {
-      iUsrSize -= Mult*Pkg.CurrentVer()->InstalledSize;
+      iUsrSize -= (signed)(Mult*Pkg.CurrentVer()->InstalledSize);
       return;
    }   
 }
@@ -310,7 +289,7 @@ void pkgDepCache::BuildGroupOrs(VerIterator const &V)
 
       /* Invert for Conflicts. We have to do this twice to get the
          right sense for a conflicts group */
-      if (D->Type == Dep::Conflicts)
+      if (D->Type == Dep::Conflicts || D->Type == Dep::Obsoletes)
 	 State = ~State;
       
       // Add to the group if we are within an or..
@@ -321,7 +300,7 @@ void pkgDepCache::BuildGroupOrs(VerIterator const &V)
 	 Group = 0;
       
       // Invert for Conflicts
-      if (D->Type == Dep::Conflicts)
+      if (D->Type == Dep::Conflicts || D->Type == Dep::Obsoletes)
 	 State = ~State;
    }	 
 }
@@ -445,7 +424,7 @@ void pkgDepCache::Update(OpProgress *Prog)
 	 {
 	    // Build the dependency state.
 	    unsigned char &State = DepState[D->ID];
-	    State = DependencyState(D);;
+	    State = DependencyState(D);
 
 	    // Add to the group if we are within an or..
 	    Group |= State;
@@ -454,7 +433,7 @@ void pkgDepCache::Update(OpProgress *Prog)
 	       Group = 0;
 
 	    // Invert for Conflicts
-	    if (D->Type == Dep::Conflicts)
+	    if (D->Type == Dep::Conflicts || D->Type == Dep::Obsoletes)
 	       State = ~State;
 	 }	 
       }
@@ -482,9 +461,9 @@ void pkgDepCache::Update(DepIterator D)
       State = DependencyState(D);
     
       // Invert for Conflicts
-      if (D->Type == Dep::Conflicts)
+      if (D->Type == Dep::Conflicts || D->Type == Dep::Obsoletes)
 	 State = ~State;
-      
+
       RemoveStates(D.ParentPkg());
       BuildGroupOrs(D.ParentVer());
       UpdateVerState(D.ParentPkg());
@@ -497,7 +476,7 @@ void pkgDepCache::Update(DepIterator D)
 /* 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);
@@ -610,8 +589,12 @@ void pkgDepCache::MarkDelete(PkgIterator const &Pkg, bool rPurge)
 // DepCache::MarkInstall - Put the package in the install state		/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst)
-{   
+void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
+			      unsigned long Depth)
+{
+   if (Depth > 100)
+      return;
+   
    // Simplifies other routines.
    if (Pkg.end() == true)
       return;
@@ -627,6 +610,10 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst)
 	 MarkKeep(Pkg);
       return;
    }
+
+   // See if there is even any possible instalation candidate
+   if (P.CandidateVer == 0)
+      return;
    
    // We dont even try to install virtual packages..
    if (Pkg->VersionList == 0)
@@ -657,7 +644,8 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst)
       // Grok or groups
       DepIterator Start = Dep;
       bool Result = true;
-      for (bool LastOR = true; Dep.end() == false && LastOR == true; Dep++)
+      unsigned Ors = 0;
+      for (bool LastOR = true; Dep.end() == false && LastOR == true; Dep++,Ors++)
       {
 	 LastOR = (Dep->CompareOp & Dep::Or) == Dep::Or;
 
@@ -676,24 +664,62 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst)
 	 continue;
       if (Pkg->CurrentVer != 0 && Start.IsCritical() == false)
 	 continue;
-
-      // Now we have to take action...
-      PkgIterator P = Start.SmartTargetPkg();
+      
+      /* If we are in an or group locate the first or that can 
+         succeed. We have already cached this.. */
+      for (; Ors > 1 && (DepState[Start->ID] & DepCVer) != DepCVer; Ors--)
+	 Start++;
+      
+      /* This bit is for processing the possibilty of an install/upgrade
+         fixing the problem */
+      SPtrArray<Version *> List = Start.AllTargets();
       if ((DepState[Start->ID] & DepCVer) == DepCVer)
       {
-	 MarkInstall(P,true);
+	 // Right, find the best version to install..
+	 Version **Cur = List;
+	 PkgIterator P = Start.TargetPkg();
+	 PkgIterator InstPkg(*Cache,0);
 	 
-	 // Set the autoflag, after MarkInstall because MarkInstall unsets it
-	 if (P->CurrentVer == 0)
-	    PkgState[P->ID].Flags |= Flag::Auto;
+	 // See if there are direct matches (at the start of the list)
+	 for (; *Cur != 0 && (*Cur)->ParentPkg == P.Index(); Cur++)
+	 {
+	    PkgIterator Pkg(*Cache,Cache->PkgP + (*Cur)->ParentPkg);
+	    if (PkgState[Pkg->ID].CandidateVer != *Cur)
+	       continue;
+	    InstPkg = Pkg;
+	    break;
+	 }
+
+	 // Select the highest priority providing package
+	 if (InstPkg.end() == false)
+	 {
+	    pkgPrioSortList(*Cache,Cur);
+	    for (; *Cur != 0; Cur++)
+	    {
+	       PkgIterator Pkg(*Cache,Cache->PkgP + (*Cur)->ParentPkg);
+	       if (PkgState[Pkg->ID].CandidateVer != *Cur)
+		  continue;
+	       InstPkg = Pkg;
+	       break;
+	    }
+	 }
+	 
+	 if (InstPkg.end() == false)
+	 {
+	    MarkInstall(InstPkg,true,Depth + 1);
 
+	    // Set the autoflag, after MarkInstall because MarkInstall unsets it
+	    if (P->CurrentVer == 0)
+	       PkgState[InstPkg->ID].Flags |= Flag::Auto;
+	 }
+	 
 	 continue;
       }
       
-      // For conflicts we just de-install the package and mark as auto
-      if (Start->Type == Dep::Conflicts)
+      /* For conflicts we just de-install the package and mark as auto,
+         Conflicts may not have or groups */
+      if (Start->Type == Dep::Conflicts || Start->Type == Dep::Obsoletes)
       {
-	 Version **List = Start.AllTargets();
 	 for (Version **I = List; *I != 0; I++)
 	 {
 	    VerIterator Ver(*this,*I);
@@ -702,7 +728,6 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst)
 	    MarkDelete(Pkg);
 	    PkgState[Pkg->ID].Flags |= Flag::Auto;
 	 }
-	 delete [] List;
 	 continue;
       }      
    }
@@ -726,6 +751,27 @@ void pkgDepCache::SetReInstall(PkgIterator const &Pkg,bool To)
    AddSizes(Pkg);
 }
 									/*}}}*/
+// DepCache::SetCandidateVersion - Change the candidate version		/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+void pkgDepCache::SetCandidateVersion(VerIterator TargetVer)
+{
+   pkgCache::PkgIterator Pkg = TargetVer.ParentPkg();
+   StateCache &P = PkgState[Pkg->ID];
+   
+   RemoveSizes(Pkg);
+   RemoveStates(Pkg);
+
+   if (P.CandidateVer == P.InstallVer)
+      P.InstallVer = (Version *)TargetVer;
+   P.CandidateVer = (Version *)TargetVer;
+   P.Update(Pkg,*this);
+   
+   AddStates(Pkg);
+   Update(Pkg);
+   AddSizes(Pkg);
+}
+									/*}}}*/
 // StateCache::Update - Compute the various static display things	/*{{{*/
 // ---------------------------------------------------------------------
 /* This is called whenever the Candidate version changes. */
@@ -770,21 +816,48 @@ const char *pkgDepCache::StateCache::StripEpoch(const char *Ver)
    return Ver;
 }
 									/*}}}*/
-// StateCache::SetCandidateVersion - Change the candidate version	/*{{{*/
+
+// Policy::GetCandidateVer - Returns the Candidate install version	/*{{{*/
 // ---------------------------------------------------------------------
-/* */
-void pkgDepCache::SetCandidateVersion(VerIterator TargetVer)
+/* The default just returns the highest available version that is not
+   a source and automatic. */
+pkgCache::VerIterator pkgDepCache::Policy::GetCandidateVer(PkgIterator Pkg)
 {
-   pkgCache::PkgIterator I = TargetVer.ParentPkg();
-   
-   RemoveSizes(I);
-   RemoveStates(I);
+   /* Not source/not automatic versions cannot be a candidate version 
+      unless they are already installed */
+   VerIterator Last(*(pkgCache *)this,0);
    
-   PkgState[I->ID].CandidateVer = (Version *) TargetVer;
-   PkgState[I->ID].Update(I, *this);
+   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)
+	    continue;
+
+	 /* Stash the highest version of a not-automatic source, we use it
+	    if there is nothing better */
+	 if ((J.File()->Flags & Flag::NotAutomatic) != 0)
+	 {
+	    if (Last.end() == true)
+	       Last = I;
+	    continue;
+	 }
+
+	 return I;
+      }
+   }
    
-   AddStates(I);
-   Update(I);
-   AddSizes(I);
+   return Last;
+}
+									/*}}}*/
+// Policy::IsImportantDep - True if the dependency is important		/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool pkgDepCache::Policy::IsImportantDep(DepIterator Dep)
+{
+   return Dep.IsCritical();
 }
 									/*}}}*/

+ 48 - 24
apt-pkg/depcache.h

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: depcache.h,v 1.13 2000/05/31 02:49:37 jgg Exp $
+// $Id: depcache.h,v 1.14 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
 
    DepCache - Dependency Extension data for the cache
@@ -35,7 +35,6 @@
    
    ##################################################################### */
 									/*}}}*/
-// Header section: pkglib
 #ifndef PKGLIB_DEPCACHE_H
 #define PKGLIB_DEPCACHE_H
 
@@ -46,7 +45,7 @@
 #include <apt-pkg/pkgcache.h>
 #include <apt-pkg/progress.h>
 
-class pkgDepCache : public pkgCache
+class pkgDepCache : protected pkgCache::Namespace
 {
    public:
    
@@ -75,16 +74,16 @@ class pkgDepCache : public pkgCache
 
       // Pointer to the install version.
       Version *InstallVer;
+      
+      // Copy of Package::Flags
+      unsigned short Flags;
+      unsigned short iFlags;           // Internal flags
 
       // 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);
@@ -110,29 +109,42 @@ class pkgDepCache : public pkgCache
    void BuildGroupOrs(VerIterator const &V);
    void UpdateVerState(PkgIterator Pkg);
 
-   bool Init(OpProgress *Prog);
-
+   // User Policy control
+   class Policy
+   {
+      public:
+      
+      virtual VerIterator GetCandidateVer(PkgIterator Pkg);
+      virtual bool IsImportantDep(DepIterator Dep);
+      
+      virtual ~Policy() {};
+   };
+     
    protected:
 
    // State information
+   pkgCache *Cache;
    StateCache *PkgState;
    unsigned char *DepState;
    
-   signed long iUsrSize;
-   unsigned long iDownloadSize;
+   double iUsrSize;
+   double iDownloadSize;
    unsigned long iInstCount;
    unsigned long iDelCount;
    unsigned long iKeepCount;
    unsigned long iBrokenCount;
    unsigned long iBadCount;
-      
+   
+   Policy *delLocalPolicy;           // For memory clean up..
+   Policy *LocalPolicy;
+   
    // Check for a matching provides
    bool CheckDep(DepIterator Dep,int Type,PkgIterator &Res);
    inline bool CheckDep(DepIterator Dep,int Type)
    {
-      PkgIterator Res(*this);
+      PkgIterator Res(*this,0);
       return CheckDep(Dep,Type,Res);
-   } 
+   }
    
    // Computes state information for deps and versions (w/o storing)
    unsigned char DependencyState(DepIterator &D);
@@ -145,17 +157,27 @@ class pkgDepCache : public pkgCache
    void Update(PkgIterator const &P);
    
    // Count manipulators
-   void AddSizes(const PkgIterator &Pkg,long Mult = 1);
+   void AddSizes(const PkgIterator &Pkg,signed 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:
 
+   // Legacy.. We look like a pkgCache
+   inline operator pkgCache &() {return *Cache;};
+   inline Header &Head() {return *Cache->HeaderP;};
+   inline PkgIterator PkgBegin() {return Cache->PkgBegin();};
+   inline PkgIterator FindPkg(string const &Name) {return Cache->FindPkg(Name);};
+
+   inline pkgCache &GetCache() {return *Cache;};
+   inline pkgVersioningSystem &VS() {return *Cache->VS;};
+   
    // Policy implementation
-   virtual VerIterator GetCandidateVer(PkgIterator Pkg,bool AllowCurrent = true);
-   virtual bool IsImportantDep(DepIterator Dep);
-         
+   inline VerIterator GetCandidateVer(PkgIterator Pkg) {return LocalPolicy->GetCandidateVer(Pkg);};
+   inline bool IsImportantDep(DepIterator Dep) {return LocalPolicy->IsImportantDep(Dep);};
+   inline Policy &GetPolicy() {return *LocalPolicy;};
+   
    // Accessors
    inline StateCache &operator [](PkgIterator const &I) {return PkgState[I->ID];};
    inline unsigned char &operator [](DepIterator const &I) {return DepState[I->ID];};
@@ -163,7 +185,8 @@ class pkgDepCache : public pkgCache
    // Manipulators
    void MarkKeep(PkgIterator const &Pkg,bool Soft = false);
    void MarkDelete(PkgIterator const &Pkg,bool Purge = false);
-   void MarkInstall(PkgIterator const &Pkg,bool AutoInst = true);
+   void MarkInstall(PkgIterator const &Pkg,bool AutoInst = true,
+		    unsigned long Depth = 0);
    void SetReInstall(PkgIterator const &Pkg,bool To);
    void SetCandidateVersion(VerIterator TargetVer);
    
@@ -171,16 +194,17 @@ class pkgDepCache : public pkgCache
    void Update(OpProgress *Prog = 0);
    
    // Size queries
-   inline signed long UsrSize() {return iUsrSize;};
-   inline unsigned long DebSize() {return iDownloadSize;};
+   inline double UsrSize() {return iUsrSize;};
+   inline double DebSize() {return iDownloadSize;};
    inline unsigned long DelCount() {return iDelCount;};
    inline unsigned long KeepCount() {return iKeepCount;};
    inline unsigned long InstCount() {return iInstCount;};
    inline unsigned long BrokenCount() {return iBrokenCount;};
    inline unsigned long BadCount() {return iBadCount;};
+
+   bool Init(OpProgress *Prog);
    
-   pkgDepCache(MMap &Map,OpProgress &Prog);
-   pkgDepCache(MMap &Map);
+   pkgDepCache(pkgCache *Cache,Policy *Plcy = 0);
    virtual ~pkgDepCache();
 };
 

+ 77 - 0
apt-pkg/indexfile.cc

@@ -0,0 +1,77 @@
+// -*- mode: cpp; mode: fold -*-
+// Description								/*{{{*/
+// $Id: indexfile.cc,v 1.2 2001/02/20 07:03:17 jgg Exp $
+/* ######################################################################
+
+   Index File - Abstraction for an index of archive/souce file.
+   
+   ##################################################################### */
+									/*}}}*/
+// Include Files							/*{{{*/
+#ifdef __GNUG__
+#pragma implementation "apt-pkg/indexfile.h"
+#endif
+
+#include <apt-pkg/indexfile.h>
+#include <apt-pkg/error.h>
+									/*}}}*/
+
+// Global list of Item supported
+static  pkgIndexFile::Type *ItmList[10];
+pkgIndexFile::Type **pkgIndexFile::Type::GlobalList = ItmList;
+unsigned long pkgIndexFile::Type::GlobalListLen = 0;
+
+// Type::Type - Constructor						/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+pkgIndexFile::Type::Type()
+{
+   ItmList[GlobalListLen] = this;
+   GlobalListLen++;   
+}
+									/*}}}*/
+// Type::GetType - Locate the type by name				/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+pkgIndexFile::Type *pkgIndexFile::Type::GetType(const char *Type)
+{
+   for (unsigned I = 0; I != GlobalListLen; I++)
+      if (strcmp(GlobalList[I]->Label,Type) == 0)
+	 return GlobalList[I];
+   return 0;
+}
+									/*}}}*/
+    
+// IndexFile::GetIndexes - Stub						/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool pkgIndexFile::GetIndexes(pkgAcquire *Owner) const
+{
+   return _error->Error("Internal Error, this index file is not downloadable");
+}
+									/*}}}*/
+// IndexFile::ArchiveInfo - Stub					/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+string pkgIndexFile::ArchiveInfo(pkgCache::VerIterator Ver) const
+{
+   return string();
+}
+									/*}}}*/
+// IndexFile::FindInCache - Stub					/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+pkgCache::PkgFileIterator pkgIndexFile::FindInCache(pkgCache &Cache) const
+{
+   return pkgCache::PkgFileIterator(Cache);
+}
+									/*}}}*/
+// IndexFile::SourceIndex - Stub					/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+string pkgIndexFile::SourceInfo(pkgSrcRecords::Parser const &Record,
+				pkgSrcRecords::File const &File) const
+{
+   return string();
+}
+									/*}}}*/

+ 80 - 0
apt-pkg/indexfile.h

@@ -0,0 +1,80 @@
+// -*- mode: cpp; mode: fold -*-
+// Description								/*{{{*/
+// $Id: indexfile.h,v 1.2 2001/02/20 07:03:17 jgg Exp $
+/* ######################################################################
+
+   Index File - Abstraction for an index of archive/source file.
+   
+   There are 3 primary sorts of index files, all represented by this 
+   class:
+   
+   Binary index files 
+   Bianry index files decribing the local system
+   Source index files
+   
+   They are all bundled together here, and the interfaces for 
+   sources.list, acquire, cache gen and record parsing all use this class
+   to acess the underlying representation.
+   
+   ##################################################################### */
+									/*}}}*/
+#ifndef PKGLIB_INDEXFILE_H
+#define PKGLIB_INDEXFILE_H
+
+#ifdef __GNUG__
+#pragma interface "apt-pkg/indexfile.h"
+#endif
+
+#include <string>
+#include <apt-pkg/pkgcache.h>
+#include <apt-pkg/srcrecords.h>
+#include <apt-pkg/pkgrecords.h>
+    
+class pkgAcquire;
+class pkgCacheGenerator;
+class OpProgress;
+class pkgIndexFile
+{
+   public:
+
+   class Type
+   {
+      public:
+      
+      // Global list of Items supported
+      static Type **GlobalList;
+      static unsigned long GlobalListLen;
+      static Type *GetType(const char *Type);
+
+      const char *Label;
+
+      virtual pkgRecords::Parser *CreatePkgParser(pkgCache::PkgFileIterator File) const {return 0;};
+      Type();
+   };
+
+   virtual const Type *GetType() const = 0;
+   
+   // Return descriptive strings of various sorts
+   virtual string ArchiveInfo(pkgCache::VerIterator Ver) const;
+   virtual string SourceInfo(pkgSrcRecords::Parser const &Record,
+			     pkgSrcRecords::File const &File) const;
+   virtual string Describe() const = 0;   
+
+   // Interface for acquire
+   virtual string ArchiveURI(string File) const {return string();};
+   virtual bool GetIndexes(pkgAcquire *Owner) const;
+
+   // Interface for the record parsers
+   virtual pkgSrcRecords::Parser *CreateSrcParser() const {return 0;};
+   
+   // Interface for the Cache Generator
+   virtual bool Exists() const = 0;
+   virtual bool HasPackages() const = 0;
+   virtual unsigned long Size() const = 0;
+   virtual bool Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const {return false;};
+   virtual pkgCache::PkgFileIterator FindInCache(pkgCache &Cache) const;
+   
+   virtual ~pkgIndexFile() {};
+};
+
+#endif

+ 82 - 23
apt-pkg/init.cc

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: init.cc,v 1.14 1998/11/25 23:54:06 jgg Exp $
+// $Id: init.cc,v 1.15 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
 
    Init - Initialize the package library
@@ -10,61 +10,120 @@
 // Include files							/*{{{*/
 #include <apt-pkg/init.h>
 #include <apt-pkg/fileutl.h>
+#include <apt-pkg/error.h>
+
+#include <apti18n.h>
 #include <config.h>
+#include <sys/stat.h>
 									/*}}}*/
 
-// pkgInitialize - Initialize the configuration class			/*{{{*/
+#define Stringfy_(x) # x
+#define Stringfy(x)  Stringfy_(x)
+const char *pkgVersion = VERSION;
+const char *pkgLibVersion = Stringfy(APT_PKG_MAJOR) "."
+                            Stringfy(APT_PKG_MINOR) "." 
+                            Stringfy(APT_PKG_RELEASE);
+const char *pkgCPU = COMMON_CPU;
+const char *pkgOS = COMMON_OS;
+    
+// pkgInitConfig - Initialize the configuration class			/*{{{*/
 // ---------------------------------------------------------------------
 /* Directories are specified in such a way that the FindDir function will
    understand them. That is, if they don't start with a / then their parent
    is prepended, this allows a fair degree of flexability. */
-bool pkgInitialize(Configuration &Cnf)
+bool pkgInitConfig(Configuration &Cnf)
 {
    // General APT things
-   Cnf.Set("APT::Architecture",ARCHITECTURE);
-
-   // State
-   Cnf.Set("Dir::State","/var/state/apt/");
-   Cnf.Set("Dir::State::lists","lists/");
+   if (strcmp(COMMON_OS,"linux") == 0 ||
+       strcmp(COMMON_OS,"unknown") == 0)
+      Cnf.Set("APT::Architecture",COMMON_CPU);
+   else
+      Cnf.Set("APT::Architecture",COMMON_OS "-" COMMON_CPU);
+   Cnf.Set("Dir","/");
    
-   /* These really should be jammed into a generic 'Local Database' engine
-      which is yet to be determined. The functions in pkgcachegen should
-      be the only users of these */
-   Cnf.Set("Dir::State::xstatus","xstatus");
-   Cnf.Set("Dir::State::userstatus","status.user");   
-   Cnf.Set("Dir::State::status","/var/lib/dpkg/status");
+   // State   
+   Cnf.Set("Dir::State","var/lib/apt/");
+   
+   /* Just in case something goes horribly wrong, we can fall back to the
+      old /var/state paths.. */
+   struct stat St;   
+   if (stat("/var/lib/apt/.",&St) != 0 &&
+       stat("/var/state/apt/.",&St) == 0)
+      Cnf.Set("Dir::State","var/state/apt/");
+       
+   Cnf.Set("Dir::State::lists","lists/");
    Cnf.Set("Dir::State::cdroms","cdroms.list");
    
    // Cache
-   Cnf.Set("Dir::Cache","/var/cache/apt/");
+   Cnf.Set("Dir::Cache","var/cache/apt/");
    Cnf.Set("Dir::Cache::archives","archives/");
    Cnf.Set("Dir::Cache::srcpkgcache","srcpkgcache.bin");
    Cnf.Set("Dir::Cache::pkgcache","pkgcache.bin");
    
    // Configuration
-   Cnf.Set("Dir::Etc","/etc/apt/");
+   Cnf.Set("Dir::Etc","etc/apt/");
    Cnf.Set("Dir::Etc::sourcelist","sources.list");
    Cnf.Set("Dir::Etc::main","apt.conf");
+   Cnf.Set("Dir::Etc::parts","apt.conf.d");
+   Cnf.Set("Dir::Etc::preferences","preferences");
    Cnf.Set("Dir::Bin::methods","/usr/lib/apt/methods");
-   Cnf.Set("Dir::Bin::dpkg","/usr/bin/dpkg");
-   
-   // Read the main config file
-   string FName = Cnf.FindFile("Dir::Etc::main");
+
    bool Res = true;
-   if (FileExists(FName) == true)
-      Res &= ReadConfigFile(Cnf,FName);
    
    // Read an alternate config file
    const char *Cfg = getenv("APT_CONFIG");
    if (Cfg != 0 && FileExists(Cfg) == true)
       Res &= ReadConfigFile(Cnf,Cfg);
    
+   // Read the configuration parts dir
+   string Parts = Cnf.FindDir("Dir::Etc::parts");
+   if (FileExists(Parts) == true)
+      Res &= ReadConfigDir(Cnf,Parts);
+      
+   // Read the main config file
+   string FName = Cnf.FindFile("Dir::Etc::main");
+   if (FileExists(FName) == true)
+      Res &= ReadConfigFile(Cnf,FName);
+   
    if (Res == false)
       return false;
    
-   if (Cnf.FindB("Debug::pkgInitialize",false) == true)
+   if (Cnf.FindB("Debug::pkgInitConfig",false) == true)
       Cnf.Dump();
       
    return true;
 }
 									/*}}}*/
+// pkgInitSystem - Initialize the _system calss				/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool pkgInitSystem(Configuration &Cnf,pkgSystem *&Sys)
+{
+   Sys = 0;
+   string Label = Cnf.Find("Apt::System","");
+   if (Label.empty() == false)
+   {
+      Sys = pkgSystem::GetSystem(Label.c_str());
+      if (Sys == 0)
+	 return _error->Error(_("Packaging system '%s' is not supported"),Label.c_str());
+   }
+   else
+   {
+      signed MaxScore = 0;
+      for (unsigned I = 0; I != pkgSystem::GlobalListLen; I++)
+      {
+	 signed Score = pkgSystem::GlobalList[I]->Score(Cnf);
+	 if (Score > MaxScore)
+	 {
+	    MaxScore = Score;
+	    Sys = pkgSystem::GlobalList[I];
+	 }
+      }
+      
+      if (Sys == 0)
+	 return _error->Error(_("Unable to determine a suitable system type"));
+   }
+   
+   return Sys->Initialize(Cnf);
+}
+									/*}}}*/

+ 25 - 3
apt-pkg/init.h

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: init.h,v 1.3 1998/07/16 06:08:37 jgg Exp $
+// $Id: init.h,v 1.4 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
 
    Init - Initialize the package library
@@ -10,12 +10,34 @@
    
    ##################################################################### */
 									/*}}}*/
-// Header section: pkglib
 #ifndef PKGLIB_INIT_H
 #define PKGLIB_INIT_H
 
 #include <apt-pkg/configuration.h>
+#include <apt-pkg/pkgsystem.h>
 
-bool pkgInitialize(Configuration &Cnf);
+// See the makefile
+#define APT_PKG_MAJOR 3
+#define APT_PKG_MINOR 1
+#define APT_PKG_RELEASE 0
+
+extern const char *pkgVersion;
+extern const char *pkgLibVersion;
+extern const char *pkgOS;
+extern const char *pkgCPU;
+
+bool pkgInitConfig(Configuration &Cnf);
+bool pkgInitSystem(Configuration &Cnf,pkgSystem *&Sys);
+
+#ifdef APT_COMPATIBILITY
+#if APT_COMPATIBILITY != 986
+#warning "Using APT_COMPATIBILITY"
+#endif
+
+inline bool pkgInitialize(Configuration &Cnf) 
+{
+   return pkgInitConfig(Cnf) && pkgInitSystem(Cnf,_system);
+};
+#endif
 
 #endif

+ 24 - 19
apt-pkg/makefile

@@ -9,36 +9,41 @@ HEADER_TARGETDIRS = apt-pkg
 # Bring in the default rules
 include ../buildlib/defaults.mak
 
-# The library name
+# The library name, don't forget to update init.h
 LIBRARY=apt-pkg
-MAJOR=2.7
-MINOR=2
+MAJOR=3.1
+MINOR=0
 SLIBS=$(PTHREADLIB)
 
 # Source code for the contributed non-core things
 SOURCE = contrib/mmap.cc contrib/error.cc contrib/strutl.cc \
          contrib/configuration.cc contrib/progress.cc contrib/cmndline.cc \
-	 contrib/md5.cc contrib/cdromutl.cc contrib/crc-16.cc
+	 contrib/md5.cc contrib/cdromutl.cc contrib/crc-16.cc \
+	 contrib/fileutl.cc
+HEADERS = mmap.h error.h configuration.h fileutl.h  cmndline.h \
+	  md5.h crc-16.h cdromutl.h strutl.h sptr.h
 
-# Source code for the main library
-SOURCE+= pkgcache.cc version.cc fileutl.cc pkgcachegen.cc depcache.cc \
+# Source code for the core main library
+SOURCE+= pkgcache.cc version.cc depcache.cc \
          orderlist.cc tagfile.cc sourcelist.cc packagemanager.cc \
-	 pkgrecords.cc algorithms.cc acquire.cc acquire-item.cc \
+	 pkgrecords.cc algorithms.cc acquire.cc\
 	 acquire-worker.cc acquire-method.cc init.cc clean.cc \
-	 srcrecords.cc cachefile.cc
+	 srcrecords.cc cachefile.cc versionmatch.cc policy.cc \
+	 pkgsystem.cc indexfile.cc pkgcachegen.cc acquire-item.cc
+HEADERS+= algorithms.h depcache.h pkgcachegen.h cacheiterators.h \
+	  orderlist.h sourcelist.h packagemanager.h tagfile.h \
+	  init.h pkgcache.h version.h progress.h pkgrecords.h \
+	  acquire.h acquire-worker.h acquire-item.h acquire-method.h \
+	  clean.h srcrecords.h cachefile.h versionmatch.h policy.h \
+	  pkgsystem.h indexfile.h
 
 # Source code for the debian specific components
-SOURCE+= deb/deblistparser.cc deb/debrecords.cc deb/dpkgpm.cc deb/dpkginit.cc \
-         deb/debsrcrecords.cc
-
-# Public apt-pkg header files
-HEADERS = algorithms.h depcache.h mmap.h pkgcachegen.h cacheiterators.h \
-          error.h orderlist.h sourcelist.h configuration.h fileutl.h \
-          packagemanager.h tagfile.h deblistparser.h init.h pkgcache.h \
-          version.h progress.h pkgrecords.h debrecords.h cmndline.h \
-	  acquire.h acquire-worker.h acquire-item.h acquire-method.h md5.h \
-	  dpkgpm.h dpkginit.h cdromutl.h strutl.h clean.h srcrecords.h \
-	  debsrcrecords.h cachefile.h crc-16.h
+# In theory the deb headers do not need to be exported..
+SOURCE+= deb/deblistparser.cc deb/debrecords.cc deb/dpkgpm.cc \
+         deb/debsrcrecords.cc deb/debversion.cc deb/debsystem.cc \
+	 deb/debindexfile.cc deb/debindexfile.cc
+HEADERS+= debversion.h debsrcrecords.h dpkgpm.h debrecords.h \
+	  deblistparser.h debsystem.h debindexfile.h
 
 HEADERS := $(addprefix apt-pkg/,$(HEADERS))
 

+ 74 - 45
apt-pkg/orderlist.cc

@@ -1,13 +1,13 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: orderlist.cc,v 1.11 2000/01/16 08:45:47 jgg Exp $
+// $Id: orderlist.cc,v 1.12 2001/02/20 07:03:17 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 
+   indicating some useful 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.
 
@@ -54,6 +54,12 @@
    after flag set. This forces them and all their dependents to be ordered
    toward the end.
    
+   There are complications in this algorithm when presented with cycles.
+   For all known practical cases it works, all cases where it doesn't work
+   is fixable by tweaking the package descriptions. However, it should be
+   possible to impove this further to make some better choices when 
+   presented with cycles. 
+   
    ##################################################################### */
 									/*}}}*/
 // Include Files							/*{{{*/
@@ -64,6 +70,8 @@
 #include <apt-pkg/depcache.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/version.h>
+#include <apt-pkg/sptr.h>
+#include <apt-pkg/configuration.h>
 									/*}}}*/
 
 pkgOrderList *pkgOrderList::Me = 0;
@@ -71,7 +79,7 @@ pkgOrderList *pkgOrderList::Me = 0;
 // OrderList::pkgOrderList - Constructor				/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-pkgOrderList::pkgOrderList(pkgDepCache &Cache) : Cache(Cache)
+pkgOrderList::pkgOrderList(pkgDepCache *pCache) : Cache(*pCache)
 {
    FileList = 0;
    Primary = 0;
@@ -79,10 +87,11 @@ pkgOrderList::pkgOrderList(pkgDepCache &Cache) : Cache(Cache)
    RevDepends = 0;
    Remove = 0;
    LoopCount = -1;
-
+   Debug = _config->FindB("Debug::pkgOrderList",false);
+   
    /* Construct the arrays, egcs 1.0.1 bug requires the package count
       hack */
-   unsigned long Size = Cache.HeaderP->PackageCount;
+   unsigned long Size = Cache.Head().PackageCount;
    Flags = new unsigned short[Size];
    End = List = new Package *[Size];
    memset(Flags,0,sizeof(*Flags)*Size);
@@ -123,9 +132,9 @@ bool pkgOrderList::IsMissing(PkgIterator Pkg)
 bool pkgOrderList::DoRun()
 {   
    // Temp list
-   unsigned long Size = Cache.HeaderP->PackageCount;
-   Package **NList = new Package *[Size];
-   AfterList = new Package *[Size];
+   unsigned long Size = Cache.Head().PackageCount;
+   SPtrArray<Package *> NList = new Package *[Size];
+   SPtrArray<Package *> AfterList = new Package *[Size];
    AfterEnd = AfterList;
    
    Depth = 0;
@@ -141,8 +150,6 @@ bool pkgOrderList::DoRun()
       if (VisitNode(PkgIterator(Cache,*I)) == false)
       {
 	 End = OldEnd;
-	 delete [] NList;
-	 delete [] AfterList;
 	 return false;
       }
    
@@ -152,8 +159,7 @@ bool pkgOrderList::DoRun()
    
    // Swap the main list to the new list
    delete [] List;
-   delete [] AfterList;
-   List = NList;
+   List = NList.UnGuard();
    return true;
 }
 									/*}}}*/
@@ -216,32 +222,43 @@ bool pkgOrderList::OrderUnpack(string *FileList)
    Me = this;
    qsort(List,End - List,sizeof(*List),&OrderCompareA);
 
+   if (Debug == true)
+      clog << "** Pass A" << endl;
    if (DoRun() == false)
       return false;
    
+   if (Debug == true)
+      clog << "** Pass B" << endl;
    Secondary = 0;
    if (DoRun() == false)
       return false;
 
+   if (Debug == true)
+      clog << "** Pass C" << endl;
    LoopCount = 0;
    RevDepends = 0;
    Remove = 0;             // Otherwise the libreadline remove problem occures
    if (DoRun() == false)
       return false;
-
+      
+   if (Debug == true)
+      clog << "** Pass D" << endl;
    LoopCount = 0;
    Primary = &pkgOrderList::DepUnPackPre;
    if (DoRun() == false)
       return false;
 
-/*   cout << "----------END" << endl;
-
-   for (iterator I = List; I != End; I++)
+   if (Debug == true)
    {
-      PkgIterator P(Cache,*I);
-      if (IsNow(P) == true)
-	 cout << P.Name() << ' ' << IsMissing(P) << ',' << IsFlag(P,After) << endl;
-   }*/
+      clog << "** Unpack ordering done" << endl;
+
+      for (iterator I = List; I != End; I++)
+      {
+	 PkgIterator P(Cache,*I);
+	 if (IsNow(P) == true)
+	    clog << P.Name() << ' ' << IsMissing(P) << ',' << IsFlag(P,After) << endl;
+      }
+   }   
 
    return true;
 }
@@ -279,6 +296,9 @@ int pkgOrderList::Score(PkgIterator Pkg)
    if ((Pkg->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
       Score += 100;
 
+   if (IsFlag(Pkg,Immediate) == true)
+      Score += 10;
+   
    for (DepIterator D = Cache[Pkg].InstVerIter(Cache).DependsList(); 
 	D.end() == false; D++)
       if (D->Type == pkgCache::Dep::PreDepends)
@@ -375,7 +395,7 @@ int pkgOrderList::OrderCompareA(const void *a, const void *b)
 									/*}}}*/
 // OrderList::OrderCompareB - Order the installation by source		/*{{{*/
 // ---------------------------------------------------------------------
-/* This orders by installation source. This is usefull to handle
+/* This orders by installation source. This is useful to handle
    inter-source breaks */
 int pkgOrderList::OrderCompareB(const void *a, const void *b)
 {
@@ -454,7 +474,7 @@ bool pkgOrderList::VisitRProvides(DepFunc F,VerIterator Ver)
 /* This routine calls visit on all providing packages. */
 bool pkgOrderList::VisitProvides(DepIterator D,bool Critical)
 {   
-   Version **List = D.AllTargets();
+   SPtrArray<Version *> List = D.AllTargets();
    for (Version **I = List; *I != 0; I++)
    {
       VerIterator Ver(Cache,*I);
@@ -463,10 +483,14 @@ bool pkgOrderList::VisitProvides(DepIterator D,bool Critical)
       if (Cache[Pkg].Keep() == true && Pkg.State() == PkgIterator::NeedsNothing)
 	 continue;
       
-      if (D->Type != pkgCache::Dep::Conflicts && Cache[Pkg].InstallVer != *I)
+      if (D->Type != pkgCache::Dep::Conflicts &&
+	  D->Type != pkgCache::Dep::Obsoletes &&
+	  Cache[Pkg].InstallVer != *I)
 	 continue;
       
-      if (D->Type == pkgCache::Dep::Conflicts && (Version *)Pkg.CurrentVer() != *I)
+      if ((D->Type == pkgCache::Dep::Conflicts ||
+	   D->Type == pkgCache::Dep::Obsoletes) &&
+	  (Version *)Pkg.CurrentVer() != *I)
 	 continue;
       
       // Skip over missing files
@@ -474,12 +498,8 @@ bool pkgOrderList::VisitProvides(DepIterator D,bool Critical)
 	 continue;
 
       if (VisitNode(Pkg) == false)
-      {
-	 delete [] List;
 	 return false;
-      }
    }
-   delete [] List;
    return true;
 }
 									/*}}}*/
@@ -496,8 +516,12 @@ bool pkgOrderList::VisitNode(PkgIterator Pkg)
        IsFlag(Pkg,AddPending) == true || IsFlag(Pkg,InList) == false)
       return true;
 
-/* for (int j = 0; j != Depth; j++) cout << ' ';
- cout << "Visit " << Pkg.Name() << endl;*/
+   if (Debug == true)
+   {
+      for (int j = 0; j != Depth; j++) clog << ' ';
+      clog << "Visit " << Pkg.Name() << endl;
+   }
+   
    Depth++;
    
    // Color grey
@@ -550,10 +574,13 @@ bool pkgOrderList::VisitNode(PkgIterator Pkg)
    
    Primary = Old;
    Depth--;
-   
-/* for (int j = 0; j != Depth; j++) cout << ' ';
-   cout << "Leave " << Pkg.Name() << ' ' << IsFlag(Pkg,Added) << ',' << IsFlag(Pkg,AddPending) << endl;*/
 
+   if (Debug == true)
+   {
+      for (int j = 0; j != Depth; j++) clog << ' ';
+      clog << "Leave " << Pkg.Name() << ' ' << IsFlag(Pkg,Added) << ',' << IsFlag(Pkg,AddPending) << endl;
+   }
+   
    return true;
 }
 									/*}}}*/
@@ -573,7 +600,8 @@ bool pkgOrderList::DepUnPackCrit(DepIterator D)
       {
 	 /* Reverse depenanices are only interested in conflicts,
 	    predepend breakage is ignored here */
-	 if (D->Type != pkgCache::Dep::Conflicts)
+	 if (D->Type != pkgCache::Dep::Conflicts && 
+	     D->Type != pkgCache::Dep::Obsoletes)
 	    continue;
 
 	 // Duplication elimination, consider only the current version
@@ -594,7 +622,9 @@ bool pkgOrderList::DepUnPackCrit(DepIterator D)
       {
 	 /* Forward critical dependencies MUST be correct before the 
 	    package can be unpacked. */
-	 if (D->Type != pkgCache::Dep::Conflicts && D->Type != pkgCache::Dep::PreDepends)
+	 if (D->Type != pkgCache::Dep::Conflicts &&
+	     D->Type != pkgCache::Dep::Obsoletes &&
+	     D->Type != pkgCache::Dep::PreDepends)
 	    continue;
 	 	 	 	 
 	 /* We wish to check if the dep is okay in the now state of the
@@ -702,7 +732,7 @@ bool pkgOrderList::DepUnPackPre(DepIterator D)
 	 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)
@@ -712,7 +742,7 @@ bool pkgOrderList::DepUnPackPre(DepIterator D)
 	 if (IsFlag(D.TargetPkg(),AddPending) == false)
 	    continue;
       }
-      
+
       // This is the loop detection
       if (IsFlag(D.TargetPkg(),Added) == true || 
 	  IsFlag(D.TargetPkg(),AddPending) == true)
@@ -875,7 +905,7 @@ bool pkgOrderList::AddLoop(DepIterator D)
 /* */
 void pkgOrderList::WipeFlags(unsigned long F)
 {
-   unsigned long Size = Cache.HeaderP->PackageCount;
+   unsigned long Size = Cache.Head().PackageCount;
    for (unsigned long I = 0; I != Size; I++)
       Flags[I] &= ~F;
 }
@@ -889,7 +919,7 @@ void pkgOrderList::WipeFlags(unsigned long F)
    this fails to produce a suitable result. */
 bool pkgOrderList::CheckDep(DepIterator D)
 {
-   Version **List = D.AllTargets();
+   SPtrArray<Version *> List = D.AllTargets();
    bool Hit = false;
    for (Version **I = List; *I != 0; I++)
    {
@@ -912,10 +942,11 @@ bool pkgOrderList::CheckDep(DepIterator D)
 	 if ((Version *)Pkg.CurrentVer() != *I || 
 	     Pkg.State() != PkgIterator::NeedsNothing)
 	    continue;
-            
+      
       /* Conflicts requires that all versions are not present, depends
          just needs one */
-      if (D->Type != pkgCache::Dep::Conflicts)
+      if (D->Type != pkgCache::Dep::Conflicts && 
+	  D->Type != pkgCache::Dep::Obsoletes)
       {
 	 /* Try to find something that does not have the after flag set
 	    if at all possible */
@@ -925,7 +956,6 @@ bool pkgOrderList::CheckDep(DepIterator D)
 	    continue;
 	 }
       
-	 delete [] List;
 	 return true;
       }
       else
@@ -933,11 +963,9 @@ bool pkgOrderList::CheckDep(DepIterator D)
 	 if (IsFlag(Pkg,After) == true)
 	    Flag(D.ParentPkg(),After);
 	 
-	 delete [] List;
 	 return false;
       }      
    }
-   delete [] List;
 
    // We found a hit, but it had the after flag set
    if (Hit == true && D->Type == pkgCache::Dep::PreDepends)
@@ -948,7 +976,8 @@ bool pkgOrderList::CheckDep(DepIterator D)
    
    /* Conflicts requires that all versions are not present, depends
       just needs one */
-   if (D->Type == pkgCache::Dep::Conflicts)
+   if (D->Type == pkgCache::Dep::Conflicts ||
+       D->Type == pkgCache::Dep::Obsoletes)
       return true;
    return false;
 }

+ 6 - 15
apt-pkg/orderlist.h

@@ -1,19 +1,18 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: orderlist.h,v 1.8 2000/01/16 08:45:47 jgg Exp $
+// $Id: orderlist.h,v 1.9 2001/02/20 07:03:17 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 
+   indicating some useful 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
 
@@ -24,19 +23,11 @@
 #include <apt-pkg/pkgcache.h>
 
 class pkgDepCache;
-class pkgOrderList
+class pkgOrderList : protected pkgCache::Namespace
 {
    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;
+   pkgDepCache &Cache;   
    typedef bool (pkgOrderList::*DepFunc)(DepIterator D);
 
    // These are the currently selected ordering functions
@@ -48,13 +39,13 @@ class pkgOrderList
    // State
    Package **End;
    Package **List;
-   Package **AfterList;
    Package **AfterEnd;
    string *FileList;
    DepIterator Loops[20];
    int LoopCount;
    int Depth;
    unsigned short *Flags;
+   bool Debug;
    
    // Main visit function
    bool VisitNode(PkgIterator Pkg);
@@ -122,7 +113,7 @@ class pkgOrderList
 
    int Score(PkgIterator Pkg);
 
-   pkgOrderList(pkgDepCache &Cache);
+   pkgOrderList(pkgDepCache *Cache);
    ~pkgOrderList();
 };
 

+ 29 - 27
apt-pkg/packagemanager.cc

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: packagemanager.cc,v 1.25 2000/05/12 04:26:42 jgg Exp $
+// $Id: packagemanager.cc,v 1.26 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
 
    Package Manager - Abstacts the package manager
@@ -16,6 +16,7 @@
 #ifdef __GNUG__
 #pragma implementation "apt-pkg/packagemanager.h"
 #endif
+
 #include <apt-pkg/packagemanager.h>
 #include <apt-pkg/orderlist.h>
 #include <apt-pkg/depcache.h>
@@ -24,12 +25,15 @@
 #include <apt-pkg/acquire-item.h>
 #include <apt-pkg/algorithms.h>
 #include <apt-pkg/configuration.h>
+#include <apt-pkg/sptr.h>
+    
+#include <apti18n.h>    
 									/*}}}*/
 
 // PM::PackageManager - Constructor					/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-pkgPackageManager::pkgPackageManager(pkgDepCache &Cache) : Cache(Cache)
+pkgPackageManager::pkgPackageManager(pkgDepCache *pCache) : Cache(*pCache)
 {
    FileNames = new string[Cache.Head().PackageCount];
    List = 0;
@@ -88,7 +92,7 @@ bool pkgPackageManager::GetArchives(pkgAcquire *Owner,pkgSourceList *Sources,
    be downloaded. */
 bool pkgPackageManager::FixMissing()
 {   
-   pkgProblemResolver Resolve(Cache);
+   pkgProblemResolver Resolve(&Cache);
    List->SetFileList(FileNames);
    
    bool Bad = false;
@@ -124,7 +128,7 @@ bool pkgPackageManager::CreateOrderList()
       return true;
    
    delete List;
-   List = new pkgOrderList(Cache);
+   List = new pkgOrderList(&Cache);
    
    bool NoImmConfigure = _config->FindB("APT::Immediate-Configure",false);
    
@@ -193,7 +197,8 @@ bool pkgPackageManager::CheckRConflicts(PkgIterator Pkg,DepIterator D,
 {
    for (;D.end() == false; D++)
    {
-      if (D->Type != pkgCache::Dep::Conflicts)
+      if (D->Type != pkgCache::Dep::Conflicts &&
+	  D->Type != pkgCache::Dep::Obsoletes)
 	 continue;
 
       // The package hasnt been changed
@@ -204,9 +209,9 @@ bool pkgPackageManager::CheckRConflicts(PkgIterator Pkg,DepIterator D,
       if (D.ParentPkg() == Pkg || D.ParentVer() != D.ParentPkg().CurrentVer())
 	 continue;
       
-      if (pkgCheckDep(D.TargetVer(),Ver,D->CompareOp) == false)
+      if (Cache.VS().CheckDep(Ver,D->CompareOp,D.TargetVer()) == false)
 	 continue;
-      
+
       if (EarlyRemove(D.ParentPkg()) == false)
 	 return _error->Error("Reverse conflicts early remove for package '%s' failed",
 			      Pkg.Name());
@@ -220,7 +225,7 @@ bool pkgPackageManager::CheckRConflicts(PkgIterator Pkg,DepIterator D,
    that the final configuration is valid. */
 bool pkgPackageManager::ConfigureAll()
 {
-   pkgOrderList OList(Cache);
+   pkgOrderList OList(&Cache);
    
    // Populate the order list
    for (pkgOrderList::iterator I = List->begin(); I != List->end(); I++)
@@ -251,14 +256,14 @@ bool pkgPackageManager::ConfigureAll()
    of it's dependents. */
 bool pkgPackageManager::SmartConfigure(PkgIterator Pkg)
 {
-   pkgOrderList OList(Cache);
+   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++)
    {
@@ -288,8 +293,7 @@ bool pkgPackageManager::DepAdd(pkgOrderList &OList,PkgIterator Pkg,int Depth)
       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);
@@ -314,7 +318,7 @@ bool pkgPackageManager::DepAdd(pkgOrderList &OList,PkgIterator Pkg,int Depth)
 	 if (Bad == false)
 	    continue;
 
-	 Version **VList = D.AllTargets();
+	 SPtrArray<Version *> VList = D.AllTargets();
 	 for (Version **I = VList; *I != 0 && Bad == true; I++)
 	 {
 	    VerIterator Ver(Cache,*I);
@@ -332,12 +336,12 @@ bool pkgPackageManager::DepAdd(pkgOrderList &OList,PkgIterator Pkg,int Depth)
 	    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)
@@ -388,11 +392,11 @@ bool pkgPackageManager::EarlyRemove(PkgIterator Pkg)
    if (IsEssential == true)
    {
       if (_config->FindB("APT::Force-LoopBreak",false) == false)
-	 return _error->Error("This installation run will require temporarily "
-			      "removing the essential package %s due to a "
-			      "Conflicts/Pre-Depends loop. This is often bad, "
-			      "but if you really want to do it, activate the "
-			      "APT::Force-LoopBreak option.",Pkg.Name());
+	 return _error->Error(_("This installation run will require temporarily "
+				"removing the essential package %s due to a "
+				"Conflicts/Pre-Depends loop. This is often bad, "
+				"but if you really want to do it, activate the "
+				"APT::Force-LoopBreak option."),Pkg.Name());
    }
    
    bool Res = SmartRemove(Pkg);
@@ -426,7 +430,7 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg)
       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 configuration");
+	    return _error->Error("Internal Error, Could not perform immediate configuration (1) on %s",Pkg.Name());
       return true;
    }
 
@@ -443,7 +447,7 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg)
       while (End->Type == pkgCache::Dep::PreDepends)
       {
 	 // Look for possible ok targets.
-	 Version **VList = Start.AllTargets();
+	 SPtrArray<Version *> VList = Start.AllTargets();
 	 bool Bad = true;
 	 for (Version **I = VList; *I != 0 && Bad == true; I++)
 	 {
@@ -473,8 +477,6 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg)
 	    Bad = !SmartConfigure(Pkg);
 	 }
 	 
-	 delete [] VList;
-
 	 /* If this or element did not match then continue on to the
 	    next or element until a matching element is found*/
 	 if (Bad == true)
@@ -487,11 +489,12 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg)
 	    break;
       }
       
-      if (End->Type == pkgCache::Dep::Conflicts)
+      if (End->Type == pkgCache::Dep::Conflicts || 
+	  End->Type == pkgCache::Dep::Obsoletes)
       {
 	 /* Look for conflicts. Two packages that are both in the install
 	    state cannot conflict so we don't check.. */
-	 Version **VList = End.AllTargets();
+	 SPtrArray<Version *> VList = End.AllTargets();
 	 for (Version **I = VList; *I != 0; I++)
 	 {
 	    VerIterator Ver(Cache,*I);
@@ -504,7 +507,6 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg)
 		  return _error->Error("Internal Error, Could not early remove %s",Pkg.Name());
 	    }
 	 }
-	 delete [] VList;
       }
    }
 
@@ -525,7 +527,7 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg)
    // 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 configuration");
+	 return _error->Error("Internal Error, Could not perform immediate configuration (2) on %s",Pkg.Name());
    
    return true;
 }

+ 8 - 17
apt-pkg/packagemanager.h

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: packagemanager.h,v 1.10 1999/07/20 05:53:33 jgg Exp $
+// $Id: packagemanager.h,v 1.11 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
 
    Package Manager - Abstacts the package manager
@@ -20,7 +20,6 @@
    
    ##################################################################### */
 									/*}}}*/
-// Header section: pkglib
 #ifndef PKGLIB_PACKAGEMANAGER_H
 #define PKGLIB_PACKAGEMANAGER_H
 
@@ -36,7 +35,7 @@ class pkgDepCache;
 class pkgSourceList;
 class pkgOrderList;
 class pkgRecords;
-class pkgPackageManager
+class pkgPackageManager : protected pkgCache::Namespace
 {
    public:
    
@@ -47,15 +46,7 @@ class pkgPackageManager
    pkgDepCache &Cache;
    pkgOrderList *List;
    bool Debug;
-   
-   // 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);
    OrderResult OrderInstall();
    bool CheckRConflicts(PkgIterator Pkg,DepIterator Dep,const char *Ver);
@@ -71,10 +62,10 @@ class pkgPackageManager
    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*/,bool /*Purge*/=false) {return false;};
+   // The Actual installation implementation
+   virtual bool Install(PkgIterator Pkg,string File) {return false;};
+   virtual bool Configure(PkgIterator Pkg) {return false;};
+   virtual bool Remove(PkgIterator Pkg,bool Purge=false) {return false;};
    virtual bool Go() {return true;};
    virtual void Reset() {};
    
@@ -86,7 +77,7 @@ class pkgPackageManager
    OrderResult DoInstall();
    bool FixMissing();
    
-   pkgPackageManager(pkgDepCache &Cache);
+   pkgPackageManager(pkgDepCache *Cache);
    virtual ~pkgPackageManager();
 };
 

+ 151 - 94
apt-pkg/pkgcache.cc

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: pkgcache.cc,v 1.31 1999/12/10 23:40:29 jgg Exp $
+// $Id: pkgcache.cc,v 1.32 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
    
    Package Cache - Accessor code for the cache
@@ -24,11 +24,15 @@
 #pragma implementation "apt-pkg/pkgcache.h"
 #pragma implementation "apt-pkg/cacheiterators.h"
 #endif 
+
 #include <apt-pkg/pkgcache.h>
 #include <apt-pkg/version.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/strutl.h>
+#include <apt-pkg/configuration.h>
 
+#include <apti18n.h>
+    
 #include <string>
 #include <sys/stat.h>
 #include <unistd.h>
@@ -48,7 +52,7 @@ pkgCache::Header::Header()
       whenever the generator changes the minor version should be bumped. */
    MajorVersion = 3;
    MinorVersion = 5;
-   Dirty = true;
+   Dirty = false;
    
    HeaderSz = sizeof(pkgCache::Header);
    PackageSz = sizeof(pkgCache::Package);
@@ -68,6 +72,8 @@ pkgCache::Header::Header()
    
    FileList = 0;
    StringList = 0;
+   VerSysName = 0;
+   Architecture = 0;
    memset(HashTable,0,sizeof(HashTable));
    memset(Pools,0,sizeof(Pools));
 }
@@ -92,9 +98,10 @@ bool pkgCache::Header::CheckSizes(Header &Against) const
 // Cache::pkgCache - Constructor					/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-pkgCache::pkgCache(MMap &Map) : Map(Map)
+pkgCache::pkgCache(MMap *Map, bool DoMap) : Map(*Map)
 {
-   ReMap();
+   if (DoMap == true)
+      ReMap();
 }
 									/*}}}*/
 // Cache::ReMap - Reopen the cache file					/*{{{*/
@@ -113,20 +120,29 @@ bool pkgCache::ReMap()
    StringItemP = (StringItem *)Map.Data();
    StrP = (char *)Map.Data();
 
-   if (Map.Size() == 0)
-      return false;
+   if (Map.Size() == 0 || HeaderP == 0)
+      return _error->Error(_("Empty package cache"));
    
    // Check the header
    Header DefHeader;
    if (HeaderP->Signature != DefHeader.Signature ||
        HeaderP->Dirty == true)
-      return _error->Error("The package cache file is corrupted");
+      return _error->Error(_("The package cache file is corrupted"));
    
    if (HeaderP->MajorVersion != DefHeader.MajorVersion ||
        HeaderP->MinorVersion != DefHeader.MinorVersion ||
        HeaderP->CheckSizes(DefHeader) == false)
-      return _error->Error("The package cache file is an incompatible version");
-   
+      return _error->Error(_("The package cache file is an incompatible version"));
+
+   // Locate our VS..
+   if (HeaderP->VerSysName == 0 ||
+       (VS = pkgVersioningSystem::GetVS(StrP + HeaderP->VerSysName)) == 0)
+      return _error->Error(_("This APT does not support the Versioning System '%s'"),StrP + HeaderP->VerSysName);
+
+   // Chcek the arhcitecture
+   if (HeaderP->Architecture == 0 ||
+       _config->Find("APT::Architecture") != StrP + HeaderP->Architecture)
+      return _error->Error(_("The package cache was build for a different architecture"));
    return true;
 }
 									/*}}}*/
@@ -168,54 +184,55 @@ pkgCache::PkgIterator pkgCache::FindPkg(string Name)
    return PkgIterator(*this,0);
 }
 									/*}}}*/
+// Cache::CompTypeDeb - Return a string describing the compare type	/*{{{*/
+// ---------------------------------------------------------------------
+/* This returns a string representation of the dependency compare 
+   type in the weird debian style.. */
+const char *pkgCache::CompTypeDeb(unsigned char Comp)
+{
+   const char *Ops[] = {"","<=",">=","<<",">>","=","!="};
+   if ((unsigned)(Comp & 0xF) < 7)
+      return Ops[Comp & 0xF];
+   return "";	 
+}
+									/*}}}*/
+// Cache::CompType - Return a string describing the compare type	/*{{{*/
+// ---------------------------------------------------------------------
+/* This returns a string representation of the dependency compare 
+   type */
+const char *pkgCache::CompType(unsigned char Comp)
+{
+   const char *Ops[] = {"","<=",">=","<",">","=","!="};
+   if ((unsigned)(Comp & 0xF) < 7)
+      return Ops[Comp & 0xF];
+   return "";	 
+}
+									/*}}}*/
+// Cache::DepType - Return a string describing the dep type		/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+const char *pkgCache::DepType(unsigned char Type)
+{
+   const char *Types[] = {"",_("Depends"),_("PreDepends"),_("Suggests"),
+                          _("Recommends"),_("Conflicts"),_("Replaces"),
+                          _("Obsoletes")};
+   if (Type < 8)
+      return Types[Type];
+   return "";
+}
+									/*}}}*/
 // Cache::Priority - Convert a priority value to a string		/*{{{*/
 // ---------------------------------------------------------------------
 /* */
 const char *pkgCache::Priority(unsigned char Prio)
 {
-   const char *Mapping[] = {0,"important","required","standard","optional","extra"};
+   const char *Mapping[] = {0,_("important"),_("required"),_("standard"),
+                            _("optional"),_("extra")};
    if (Prio < _count(Mapping))
       return Mapping[Prio];
    return 0;
 }
 									/*}}}*/
-// Cache::GetCandidateVer - Returns the Candidate install version	/*{{{*/
-// ---------------------------------------------------------------------
-/* The default just returns the highest available version that is not
-   a source and automatic */
-pkgCache::VerIterator pkgCache::GetCandidateVer(PkgIterator Pkg,
-						bool AllowCurrent)
-{
-   /* Not source/not automatic versions cannot be a candidate version 
-      unless they are already installed */
-   VerIterator Last(*this,0);
-   
-   for (VerIterator I = Pkg.VersionList(); I.end() == false; I++)
-   {
-      if (Pkg.CurrentVer() == I && AllowCurrent == true)
-	 return I;
-      
-      for (VerFileIterator J = I.FileList(); J.end() == false; J++)
-      {
-	 if ((J.File()->Flags & Flag::NotSource) != 0)
-	    continue;
-
-	 /* Stash the highest version of a not-automatic source, we use it
-	    if there is nothing better */
-	 if ((J.File()->Flags & Flag::NotAutomatic) != 0)
-	 {
-	    if (Last.end() == true)
-	       Last = I;
-	    continue;
-	 }
-	 
-	 return I;
-      }   
-   }
-   
-   return Last;
-}
-									/*}}}*/
 
 // Bases for iterator classes						/*{{{*/
 void pkgCache::VerIterator::_dummy() {}
@@ -230,9 +247,9 @@ void pkgCache::PkgIterator::operator ++(int)
    // Follow the current links
    if (Pkg != Owner->PkgP)
       Pkg = Owner->PkgP + Pkg->NextPackage;
-   
+
    // Follow the hash table
-   while (Pkg == Owner->PkgP && HashIndex < (signed)_count(Owner->HeaderP->HashTable))
+   while (Pkg == Owner->PkgP && (HashIndex+1) < (signed)_count(Owner->HeaderP->HashTable))
    {
       HashIndex++;
       Pkg = Owner->PkgP + Owner->HeaderP->HashTable[HashIndex];
@@ -265,7 +282,8 @@ pkgCache::PkgIterator::OkState pkgCache::PkgIterator::State() const
    conflicts. */
 bool pkgCache::DepIterator::IsCritical()
 {
-   if (Dep->Type == pkgCache::Dep::Conflicts || 
+   if (Dep->Type == pkgCache::Dep::Conflicts ||
+       Dep->Type == pkgCache::Dep::Obsoletes ||
        Dep->Type == pkgCache::Dep::Depends ||
        Dep->Type == pkgCache::Dep::PreDepends)
       return true;
@@ -280,7 +298,11 @@ bool pkgCache::DepIterator::IsCritical()
    then it returned. Otherwise the providing list is looked at to 
    see if there is one one unique providing package if so it is returned.
    Otherwise true is returned and the target package is set. The return
-   result indicates whether the node should be expandable */
+   result indicates whether the node should be expandable 
+ 
+   In Conjunction with the DepCache the value of Result may not be 
+   super-good since the policy may have made it uninstallable. Using
+   AllTargets is better in this case. */
 bool pkgCache::DepIterator::SmartTargetPkg(PkgIterator &Result)
 {
    Result = TargetPkg();
@@ -314,17 +336,19 @@ bool pkgCache::DepIterator::SmartTargetPkg(PkgIterator &Result)
       if (PStart.OwnerPkg() != P.OwnerPkg())
 	 break;
    }
+
+   Result = PStart.OwnerPkg();
    
    // Check for non dups
    if (P.end() != true)
       return true;
-   Result = PStart.OwnerPkg();
+   
    return false;
 }
 									/*}}}*/
 // DepIterator::AllTargets - Returns the set of all possible targets	/*{{{*/
 // ---------------------------------------------------------------------
-/* This is a more usefull version of TargetPkg() that follows versioned
+/* This is a more useful version of TargetPkg() that follows versioned
    provides. It includes every possible package-version that could satisfy
    the dependency. The last item in the list has a 0. The resulting pointer
    must be delete [] 'd */
@@ -340,10 +364,11 @@ pkgCache::Version **pkgCache::DepIterator::AllTargets()
       // Walk along the actual package providing versions
       for (VerIterator I = DPkg.VersionList(); I.end() == false; I++)
       {
-	 if (pkgCheckDep(TargetVer(),I.VerStr(),Dep->CompareOp) == false)
+	 if (Owner->VS->CheckDep(I.VerStr(),Dep->CompareOp,TargetVer()) == false)
 	    continue;
 
-	 if (Dep->Type == pkgCache::Dep::Conflicts && 
+	 if ((Dep->Type == pkgCache::Dep::Conflicts ||
+	      Dep->Type == pkgCache::Dep::Obsoletes) &&
 	     ParentPkg() == I.ParentPkg())
 	    continue;
 	 
@@ -355,10 +380,11 @@ pkgCache::Version **pkgCache::DepIterator::AllTargets()
       // Follow all provides
       for (PrvIterator I = DPkg.ProvidesList(); I.end() == false; I++)
       {
-	 if (pkgCheckDep(TargetVer(),I.ProvideVersion(),Dep->CompareOp) == false)
+	 if (Owner->VS->CheckDep(I.ProvideVersion(),Dep->CompareOp,TargetVer()) == false)
 	    continue;
 	 
-	 if (Dep->Type == pkgCache::Dep::Conflicts && 
+	 if ((Dep->Type == pkgCache::Dep::Conflicts ||
+	      Dep->Type == pkgCache::Dep::Obsoletes) &&
 	     ParentPkg() == I.OwnerPkg())
 	    continue;
 	 
@@ -383,30 +409,6 @@ pkgCache::Version **pkgCache::DepIterator::AllTargets()
    return Res;
 }
 									/*}}}*/
-// DepIterator::CompType - Return a string describing the compare type	/*{{{*/
-// ---------------------------------------------------------------------
-/* This returns a string representation of the dependency compare 
-   type */
-const char *pkgCache::DepIterator::CompType()
-{
-   const char *Ops[] = {"","<=",">=","<",">","=","!="};
-   if ((unsigned)(Dep->CompareOp & 0xF) < 7)
-      return Ops[Dep->CompareOp & 0xF];
-   return "";	 
-}
-									/*}}}*/
-// DepIterator::DepType - Return a string describing the dep type	/*{{{*/
-// ---------------------------------------------------------------------
-/* */
-const char *pkgCache::DepIterator::DepType()
-{
-   const char *Types[] = {"","Depends","PreDepends","Suggests",
-                          "Recommends","Conflicts","Replaces"};
-   if (Dep->Type < 7)
-      return Types[Dep->Type];
-   return "";
-}
-									/*}}}*/
 // DepIterator::GlobOr - Compute an OR group				/*{{{*/
 // ---------------------------------------------------------------------
 /* This Takes an iterator, iterates past the current dependency grouping
@@ -462,18 +464,6 @@ bool pkgCache::VerIterator::Downloadable() const
    return false;
 }
 									/*}}}*/
-// VerIterator::PriorityType - Return a string describing the priority	/*{{{*/
-// ---------------------------------------------------------------------
-/* */
-const char *pkgCache::VerIterator::PriorityType()
-{
-   const char *Types[] = {"","Important","Required","Standard",
-                          "Optional","Extra"};
-   if (Ver->Priority < 6)
-      return Types[Ver->Priority];
-   return "";
-}
-									/*}}}*/
 // VerIterator::Automatic - Check if this version is 'automatic'	/*{{{*/
 // ---------------------------------------------------------------------
 /* This checks to see if any of the versions files are not NotAutomatic. 
@@ -497,13 +487,80 @@ pkgCache::VerFileIterator pkgCache::VerIterator::NewestFile() const
    VerFileIterator Highest = Files;
    for (; Files.end() == false; Files++)
    {
-      if (pkgVersionCompare(Files.File().Version(),Highest.File().Version()) > 0)
+      if (Owner->VS->CmpReleaseVer(Files.File().Version(),Highest.File().Version()) > 0)
 	 Highest = Files;
    }
    
    return Highest;
 }
 									/*}}}*/
+// VerIterator::RelStr - Release description string			/*{{{*/
+// ---------------------------------------------------------------------
+/* This describes the version from a release-centric manner. The output is a 
+   list of Label:Version/Archive */
+string pkgCache::VerIterator::RelStr()
+{
+   bool First = true;
+   string Res;
+   for (pkgCache::VerFileIterator I = this->FileList(); I.end() == false; I++)
+   {
+      // Do not print 'not source' entries'
+      pkgCache::PkgFileIterator File = I.File();
+      if ((File->Flags & pkgCache::Flag::NotSource) == pkgCache::Flag::NotSource)
+	 continue;
+
+      // See if we have already printed this out..
+      bool Seen = false;
+      for (pkgCache::VerFileIterator J = this->FileList(); I != J; J++)
+      {
+	 pkgCache::PkgFileIterator File2 = J.File();
+	 if (File2->Label == 0 || File->Label == 0)
+	    continue;
+
+	 if (strcmp(File.Label(),File2.Label()) != 0)
+	    continue;
+	 
+	 if (File2->Version == File->Version)
+	 {
+	    Seen = true;
+	    break;
+	 }
+	 if (File2->Version == 0)
+	    break;
+	 if (strcmp(File.Version(),File2.Version()) == 0)
+	    Seen = true;
+      }
+      
+      if (Seen == true)
+	 continue;
+      
+      if (First == false)
+	 Res += ", ";
+      else
+	 First = false;
+      
+      if (File->Label != 0)
+	 Res = Res + File.Label() + ':';
+
+      if (File->Archive != 0)
+      {
+	 if (File->Version == 0)
+	    Res += File.Archive();
+	 else
+	    Res = Res + File.Version() + '/' +  File.Archive();
+      }
+      else
+      {
+	 // No release file, print the host name that this came from
+	 if (File->Site == 0 || File.Site()[0] == 0)
+	    Res += "localhost";
+	 else
+	    Res += File.Site();
+      }      
+   }   
+   return Res;
+}
+									/*}}}*/
 // PkgFileIterator::IsOk - Checks if the cache is in sync with the file	/*{{{*/
 // ---------------------------------------------------------------------
 /* This stats the file and compares its stats with the ones that were

+ 47 - 17
apt-pkg/pkgcache.h

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: pkgcache.h,v 1.22 1999/07/30 02:54:25 jgg Exp $
+// $Id: pkgcache.h,v 1.23 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
    
    Cache - Structure definitions for the cache file
@@ -16,7 +16,6 @@
    
    ##################################################################### */
 									/*}}}*/
-// Header section: pkglib
 #ifndef PKGLIB_PKGCACHE_H
 #define PKGLIB_PKGCACHE_H
 
@@ -27,7 +26,8 @@
 #include <string>
 #include <time.h>
 #include <apt-pkg/mmap.h>
-
+    
+class pkgVersioningSystem;
 class pkgCache
 {
    public:
@@ -48,18 +48,20 @@ class pkgCache
    class PrvIterator;
    class PkgFileIterator;
    class VerFileIterator;
-   friend PkgIterator;
-   friend VerIterator;
-   friend DepIterator;
-   friend PrvIterator;
-   friend PkgFileIterator;
-   friend VerFileIterator;
+   friend class PkgIterator;
+   friend class VerIterator;
+   friend class DepIterator;
+   friend class PrvIterator;
+   friend class PkgFileIterator;
+   friend class VerFileIterator;
+   
+   class Namespace;
    
    // These are all the constants used in the cache structures
    struct Dep
    {
       enum DepType {Depends=1,PreDepends=2,Suggests=3,Recommends=4,
-	 Conflicts=5,Replaces=6};
+	 Conflicts=5,Replaces=6,Obsoletes=7};
       enum DepCompareOp {Or=0x10,NoOp=0,LessEq=0x1,GreaterEq=0x2,Less=0x3,
 	 Greater=0x4,Equals=0x5,NotEquals=0x6};
    };
@@ -104,7 +106,8 @@ class pkgCache
    virtual bool ReMap();
    inline bool Sync() {return Map.Sync();};
    inline MMap &GetMap() {return Map;};
-   
+   inline void *DataEnd() {return ((unsigned char *)Map.Data()) + Map.Size();};
+      
    // String hashing function (512 range)
    inline unsigned long Hash(string S) const {return sHash(S);};
    inline unsigned long Hash(const char *S) const {return sHash(S);};
@@ -119,9 +122,16 @@ class pkgCache
    inline PkgIterator PkgEnd();
    inline PkgFileIterator FileBegin();
    inline PkgFileIterator FileEnd();
-   VerIterator GetCandidateVer(PkgIterator Pkg,bool AllowCurrent = true);
+
+   // Make me a function
+   pkgVersioningSystem *VS;
+   
+   // Converters
+   static const char *CompTypeDeb(unsigned char Comp);
+   static const char *CompType(unsigned char Comp);
+   static const char *DepType(unsigned char Dep);
    
-   pkgCache(MMap &Map);
+   pkgCache(MMap *Map,bool DoMap = true);
    virtual ~pkgCache() {};
 };
 
@@ -154,6 +164,8 @@ struct pkgCache::Header
    // Offsets
    map_ptrloc FileList;              // struct PackageFile
    map_ptrloc StringList;            // struct StringItem
+   map_ptrloc VerSysName;            // StringTable
+   map_ptrloc Architecture;          // StringTable
    unsigned long MaxVerFileSize;
 
    /* Allocation pools, there should be one of these for each structure
@@ -172,9 +184,7 @@ struct pkgCache::Package
    // Pointers
    map_ptrloc Name;              // Stringtable
    map_ptrloc VersionList;       // Version
-   map_ptrloc TargetVer;         // Version
    map_ptrloc CurrentVer;        // Version
-   map_ptrloc TargetDist;        // StringTable (StringItem)
    map_ptrloc Section;           // StringTable (StringItem)
       
    // Linked list 
@@ -201,6 +211,8 @@ struct pkgCache::PackageFile
    map_ptrloc Origin;          // Stringtable
    map_ptrloc Label;           // Stringtable
    map_ptrloc Architecture;    // Stringtable
+   map_ptrloc Site;            // Stringtable
+   map_ptrloc IndexType;       // Stringtable
    unsigned long Size;            
    unsigned long Flags;
    
@@ -249,7 +261,7 @@ struct pkgCache::Dependency
    // Specific types of depends
    unsigned char Type;
    unsigned char CompareOp;
-   unsigned short ID;
+   unsigned short ID;   
 };
 
 struct pkgCache::Provides
@@ -274,8 +286,26 @@ inline pkgCache::PkgIterator pkgCache::PkgBegin()
 inline pkgCache::PkgIterator pkgCache::PkgEnd() 
        {return PkgIterator(*this,PkgP);};
 inline pkgCache::PkgFileIterator pkgCache::FileBegin()
-       {return PkgFileIterator(*this);};
+       {return PkgFileIterator(*this,PkgFileP + HeaderP->FileList);};
 inline pkgCache::PkgFileIterator pkgCache::FileEnd()
        {return PkgFileIterator(*this,PkgFileP);};
 
+// Oh I wish for Real Name Space Support
+class pkgCache::Namespace
+{   
+   public:
+
+   typedef pkgCache::PkgIterator PkgIterator;
+   typedef pkgCache::VerIterator VerIterator;
+   typedef pkgCache::DepIterator DepIterator;
+   typedef pkgCache::PrvIterator PrvIterator;
+   typedef pkgCache::PkgFileIterator PkgFileIterator;
+   typedef pkgCache::VerFileIterator VerFileIterator;   
+   typedef pkgCache::Version Version;
+   typedef pkgCache::Package Package;
+   typedef pkgCache::Header Header;
+   typedef pkgCache::Dep Dep;
+   typedef pkgCache::Flag Flag;
+};
+
 #endif

+ 249 - 439
apt-pkg/pkgcachegen.cc

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: pkgcachegen.cc,v 1.45 2000/01/14 06:26:36 jgg Exp $
+// $Id: pkgcachegen.cc,v 1.46 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
    
    Package Cache Generator - Generator for the cache structure.
@@ -14,15 +14,20 @@
 #pragma implementation "apt-pkg/pkgcachegen.h"
 #endif
 
+#define APT_COMPATIBILITY 986
+
 #include <apt-pkg/pkgcachegen.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/version.h>
 #include <apt-pkg/progress.h>
 #include <apt-pkg/sourcelist.h>
 #include <apt-pkg/configuration.h>
-#include <apt-pkg/deblistparser.h>
 #include <apt-pkg/strutl.h>
+#include <apt-pkg/sptr.h>
+#include <apt-pkg/pkgsystem.h>
 
+#include <apti18n.h>
+    
 #include <sys/stat.h>
 #include <unistd.h>
 #include <errno.h>
@@ -33,23 +38,42 @@
 // CacheGenerator::pkgCacheGenerator - Constructor			/*{{{*/
 // ---------------------------------------------------------------------
 /* We set the diry flag and make sure that is written to the disk */
-pkgCacheGenerator::pkgCacheGenerator(DynamicMMap &Map,OpProgress &Prog) :
-                    Map(Map), Cache(Map), Progress(&Prog)
+pkgCacheGenerator::pkgCacheGenerator(DynamicMMap *pMap,OpProgress *Prog) :
+                    Map(*pMap), Cache(pMap,false), Progress(Prog)
 {
    CurrentFile = 0;
+   memset(UniqHash,0,sizeof(UniqHash));
    
    if (_error->PendingError() == true)
       return;
-   
+
    if (Map.Size() == 0)
    {
+      // Setup the map interface..
+      Cache.HeaderP = (pkgCache::Header *)Map.Data();
       Map.RawAllocate(sizeof(pkgCache::Header));
+      Map.UsePools(*Cache.HeaderP->Pools,sizeof(Cache.HeaderP->Pools)/sizeof(Cache.HeaderP->Pools[0]));
+      
+      // Starting header
       *Cache.HeaderP = pkgCache::Header();
+      Cache.HeaderP->VerSysName = Map.WriteString(_system->VS->Label);
+      Cache.HeaderP->Architecture = Map.WriteString(_config->Find("APT::Architecture"));
+      Cache.ReMap(); 
    }
+   else
+   {
+      // Map directly from the existing file
+      Cache.ReMap(); 
+      Map.UsePools(*Cache.HeaderP->Pools,sizeof(Cache.HeaderP->Pools)/sizeof(Cache.HeaderP->Pools[0]));
+      if (Cache.VS != _system->VS)
+      {
+	 _error->Error(_("Cache has an incompatible versioning system"));
+	 return;
+      }      
+   }
+   
    Cache.HeaderP->Dirty = true;
    Map.Sync(0,sizeof(pkgCache::Header));
-   Map.UsePools(*Cache.HeaderP->Pools,sizeof(Cache.HeaderP->Pools)/sizeof(Cache.HeaderP->Pools[0]));
-   memset(UniqHash,0,sizeof(UniqHash));
 }
 									/*}}}*/
 // CacheGenerator::~pkgCacheGenerator - Destructor 			/*{{{*/
@@ -86,7 +110,7 @@ bool pkgCacheGenerator::MergeList(ListParser &List,
       
       pkgCache::PkgIterator Pkg;
       if (NewPackage(Pkg,PackageName) == false)
-	 return _error->Error("Error occured while processing %s (NewPackage)",PackageName.c_str());
+	 return _error->Error(_("Error occured while processing %s (NewPackage)"),PackageName.c_str());
       Counter++;
       if (Counter % 100 == 0 && Progress != 0)
 	 Progress->Progress(List.Offset());
@@ -98,7 +122,7 @@ bool pkgCacheGenerator::MergeList(ListParser &List,
       if (Version.empty() == true)
       {
 	 if (List.UsePackage(Pkg,pkgCache::VerIterator(Cache)) == false)
-	    return _error->Error("Error occured while processing %s (UsePackage1)",PackageName.c_str());
+	    return _error->Error(_("Error occured while processing %s (UsePackage1)"),PackageName.c_str());
 	 continue;
       }
 
@@ -107,7 +131,7 @@ bool pkgCacheGenerator::MergeList(ListParser &List,
       int Res = 1;
       for (; Ver.end() == false; Last = &Ver->NextVer, Ver++)
       {
-	 Res = pkgVersionCompare(Version.begin(),Version.end(),Ver.VerStr(),
+	 Res = Cache.VS->DoCmpVersion(Version.begin(),Version.end(),Ver.VerStr(),
 				 Ver.VerStr() + strlen(Ver.VerStr()));
 	 if (Res >= 0)
 	    break;
@@ -119,10 +143,10 @@ bool pkgCacheGenerator::MergeList(ListParser &List,
       if (Res == 0 && Ver->Hash == Hash)
       {
 	 if (List.UsePackage(Pkg,Ver) == false)
-	    return _error->Error("Error occured while processing %s (UsePackage2)",PackageName.c_str());
+	    return _error->Error(_("Error occured while processing %s (UsePackage2)"),PackageName.c_str());
 
 	 if (NewFileVer(Ver,List) == false)
-	    return _error->Error("Error occured while processing %s (NewFileVer1)",PackageName.c_str());
+	    return _error->Error(_("Error occured while processing %s (NewFileVer1)"),PackageName.c_str());
 	 
 	 // Read only a single record and return
 	 if (OutVer != 0)
@@ -139,7 +163,7 @@ bool pkgCacheGenerator::MergeList(ListParser &List,
       {
 	 for (; Ver.end() == false; Last = &Ver->NextVer, Ver++)
 	 {
-	    Res = pkgVersionCompare(Version.begin(),Version.end(),Ver.VerStr(),
+	    Res = Cache.VS->DoCmpVersion(Version.begin(),Version.end(),Ver.VerStr(),
 				    Ver.VerStr() + strlen(Ver.VerStr()));
 	    if (Res != 0)
 	       break;
@@ -151,13 +175,13 @@ bool pkgCacheGenerator::MergeList(ListParser &List,
       Ver->ParentPkg = Pkg.Index();
       Ver->Hash = Hash;
       if (List.NewVersion(Ver) == false)
-	 return _error->Error("Error occured while processing %s (NewVersion1)",PackageName.c_str());
+	 return _error->Error(_("Error occured while processing %s (NewVersion1)"),PackageName.c_str());
 
       if (List.UsePackage(Pkg,Ver) == false)
-	 return _error->Error("Error occured while processing %s (UsePackage3)",PackageName.c_str());
+	 return _error->Error(_("Error occured while processing %s (UsePackage3)"),PackageName.c_str());
       
       if (NewFileVer(Ver,List) == false)
-	 return _error->Error("Error occured while processing %s (NewVersion2)",PackageName.c_str());
+	 return _error->Error(_("Error occured while processing %s (NewVersion2)"),PackageName.c_str());
 
       // Read only a single record and return
       if (OutVer != 0)
@@ -288,7 +312,7 @@ bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver,
    // Probe the reverse dependency list for a version string that matches
    if (Version.empty() == false)
    {
-/*      for (pkgCache::DepIterator I = Pkg.RevDependsList(); I.end() == false; I++, Hit++)
+/*      for (pkgCache::DepIterator I = Pkg.RevDependsList(); I.end() == false; I++)
 	 if (I->Version != 0 && I.TargetVer() == Version)
 	    Dep->Version = I->Version;*/
       if (Dep->Version == 0)
@@ -342,7 +366,7 @@ bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver,
    Prv->Version = Ver.Index();
    Prv->NextPkgProv = Ver->ProvidesList;
    Ver->ProvidesList = Prv.Index();
-   if (Version.empty() == false && (Prv->Version = WriteString(Version)) == 0)
+   if (Version.empty() == false && (Prv->ProvideVersion = WriteString(Version)) == 0)
       return false;
    
    // Locate the target package
@@ -361,13 +385,11 @@ bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver,
 // CacheGenerator::SelectFile - Select the current file being parsed	/*{{{*/
 // ---------------------------------------------------------------------
 /* This is used to select which file is to be associated with all newly
-   added versions. */
-bool pkgCacheGenerator::SelectFile(string File,unsigned long Flags)
+   added versions. The caller is responsible for setting the IMS fields. */
+bool pkgCacheGenerator::SelectFile(string File,string Site,
+				   const pkgIndexFile &Index,
+				   unsigned long Flags)
 {
-   struct stat Buf;
-   if (stat(File.c_str(),&Buf) == -1)
-      return _error->Errno("stat","Couldn't stat ",File.c_str());
-   
    // Get some space for the structure
    CurrentFile = Cache.PkgFileP + Map.Allocate(sizeof(*CurrentFile));
    if (CurrentFile == Cache.PkgFileP)
@@ -375,20 +397,20 @@ bool pkgCacheGenerator::SelectFile(string File,unsigned long Flags)
    
    // Fill it in
    CurrentFile->FileName = Map.WriteString(File);
-   CurrentFile->Size = Buf.st_size;
-   CurrentFile->mtime = Buf.st_mtime;
+   CurrentFile->Site = WriteUniqString(Site);
    CurrentFile->NextFile = Cache.HeaderP->FileList;
    CurrentFile->Flags = Flags;
    CurrentFile->ID = Cache.HeaderP->PackageFileCount;
+   CurrentFile->IndexType = WriteUniqString(Index.GetType()->Label);
    PkgFileName = File;
    Cache.HeaderP->FileList = CurrentFile - Cache.PkgFileP;
    Cache.HeaderP->PackageFileCount++;
-      
+
    if (CurrentFile->FileName == 0)
       return false;
    
    if (Progress != 0)
-      Progress->SubProgress(Buf.st_size);
+      Progress->SubProgress(Index.Size());
    return true;
 }
 									/*}}}*/
@@ -443,491 +465,279 @@ unsigned long pkgCacheGenerator::WriteUniqString(const char *S,
 }
 									/*}}}*/
 
-// SrcCacheCheck - Check if the source package cache is uptodate	/*{{{*/
+// CheckValidity - Check that a cache is up-to-date			/*{{{*/
 // ---------------------------------------------------------------------
-/* The source cache is checked against the source list and the files 
-   on disk, any difference results in a false. */
-bool pkgSrcCacheCheck(pkgSourceList &List)
+/* This just verifies that each file in the list of index files exists,
+   has matching attributes with the cache and the cache does not have
+   any extra files. */
+static bool CheckValidity(string CacheFile,pkgIndexFile **Start,
+			  pkgIndexFile **End,MMap **OutMap = 0)
 {
-   if (_error->PendingError() == true)
-      return false;
-
-   string CacheFile = _config->FindFile("Dir::Cache::srcpkgcache");
-   string ListDir = _config->FindDir("Dir::State::lists");
-
-   // Count the number of missing files
-   int Missing = 0;
-   for (pkgSourceList::const_iterator I = List.begin(); I != List.end(); I++)
-   {
-      // Only cache deb source types.
-      if (I->Type != pkgSourceList::Item::Deb)
-      {
-	 Missing++;
-	 continue;
-      }
-      
-      string File = ListDir + URItoFileName(I->PackagesURI());
-      struct stat Buf;
-      if (stat(File.c_str(),&Buf) != 0)
-      {
-	 // Old format file name.. rename it
-	 if (File[0] == '_' && stat(File.c_str()+1,&Buf) == 0)
-	 {
-	    if (rename(File.c_str()+1,File.c_str()) != 0)
-	       return _error->Errno("rename","Failed to rename %s to %s",
-				    File.c_str()+1,File.c_str());
-	    continue;
-	 }	 
-	 
-	 _error->WarningE("stat","Couldn't stat source package list '%s' (%s)",
-			  I->PackagesInfo().c_str(),File.c_str());	 
-	 Missing++;
-      }      
-   }
-   
-   // Open the source package cache
-   if (FileExists(CacheFile) == false)
+   // No file, certainly invalid
+   if (CacheFile.empty() == true || FileExists(CacheFile) == false)
       return false;
    
+   // Map it
    FileFd CacheF(CacheFile,FileFd::ReadOnly);
-   if (_error->PendingError() == true)
-   {
-      _error->Discard();
-      return false;
-   }
-   
-   MMap Map(CacheF,MMap::Public | MMap::ReadOnly);
-   if (_error->PendingError() == true || Map.Size() == 0)
-   {
-      _error->Discard();
-      return false;
-   }
-   
+   SPtr<MMap> Map = new MMap(CacheF,MMap::Public | MMap::ReadOnly);
    pkgCache Cache(Map);
-   if (_error->PendingError() == true)
+   if (_error->PendingError() == true || Map->Size() == 0)
    {
       _error->Discard();
       return false;
    }
-
-   // They are certianly out of sync
-   if (Cache.Head().PackageFileCount != List.size() - Missing)
-      return false;
    
-   for (pkgCache::PkgFileIterator F(Cache); F.end() == false; F++)
-   {      
-      // Search for a match in the source list
-      bool Bad = true;
-      for (pkgSourceList::const_iterator I = List.begin(); 
-	   I != List.end(); I++)
+   /* Now we check every index file, see if it is in the cache,
+      verify the IMS data and check that it is on the disk too.. */
+   SPtrArray<bool> Visited = new bool[Cache.HeaderP->PackageFileCount];
+   memset(Visited,0,sizeof(*Visited)*Cache.HeaderP->PackageFileCount);
+   for (; Start != End; Start++)
+   {
+      if ((*Start)->HasPackages() == false)
+	 continue;
+      
+      if ((*Start)->Exists() == false)
       {
-	 // Only cache deb source types.
-	 if (I->Type != pkgSourceList::Item::Deb)
-	    continue;
-	 
-	 string File = ListDir + URItoFileName(I->PackagesURI());
-	 if (F.FileName() == File)
-	 {
-	    Bad = false;
-	    break;
-	 }
+	 _error->WarningE("stat",_("Couldn't stat source package list %s"),
+			  (*Start)->Describe().c_str());
+	 continue;
       }
-      
-      // Check if the file matches what was cached
-      Bad |= !F.IsOk();
-      if (Bad == true)
+
+      // FindInCache is also expected to do an IMS check.
+      pkgCache::PkgFileIterator File = (*Start)->FindInCache(Cache);
+      if (File.end() == true)
 	 return false;
+      
+      Visited[File->ID] = true;
    }
    
-   return true;
-}
-									/*}}}*/
-// PkgCacheCheck - Check if the package cache is uptodate		/*{{{*/
-// ---------------------------------------------------------------------
-/* This does a simple check of all files used to compose the cache */
-bool pkgPkgCacheCheck(string CacheFile)
-{
-   if (_error->PendingError() == true)
-      return false;
-   
-   // Open the source package cache
-   if (FileExists(CacheFile) == false)
-      return false;
-   
-   FileFd CacheF(CacheFile,FileFd::ReadOnly);
-   if (_error->PendingError() == true)
-   {
-      _error->Discard();
-      return false;
-   }
-   
-   MMap Map(CacheF,MMap::Public | MMap::ReadOnly);
-   if (_error->PendingError() == true || Map.Size() == 0)
-   {
-      _error->Discard();
-      return false;
-   }
+   for (unsigned I = 0; I != Cache.HeaderP->PackageFileCount; I++)
+      if (Visited[I] == false)
+	 return false;
    
-   pkgCache Cache(Map);
    if (_error->PendingError() == true)
    {
       _error->Discard();
       return false;
    }
-
-   // Status files that must be in the cache
-   string Status[3];
-   Status[0] = _config->FindFile("Dir::State::xstatus");
-   Status[1]= _config->FindFile("Dir::State::userstatus");
-   Status[2] = _config->FindFile("Dir::State::status");
-   
-   // Cheack each file
-   for (pkgCache::PkgFileIterator F(Cache); F.end() == false; F++)
-   {
-      if (F.IsOk() == false)
-	 return false;
-      
-      // See if this is one of the status files
-      for (int I = 0; I != 3; I++)
-	 if (F.FileName() == Status[I])
-	    Status[I] = string();
-   }
-   
-   // Make sure all the status files are loaded.
-   for (int I = 0; I != 3; I++)
-   {
-      if (Status[I].empty() == false && FileExists(Status[I]) == true)
-	 return false;
-   }   
-   
-   return true;
-}
-									/*}}}*/
-// AddStatusSize - Add the size of the status files			/*{{{*/
-// ---------------------------------------------------------------------
-/* This adds the size of all the status files to the size counter */
-bool pkgAddStatusSize(unsigned long &TotalSize)
-{
-   // Grab the file names
-   string xstatus = _config->FindFile("Dir::State::xstatus");
-   string userstatus = _config->FindFile("Dir::State::userstatus");
-   string status = _config->FindFile("Dir::State::status");
-   
-   // Grab the sizes
-   struct stat Buf;
-   if (stat(xstatus.c_str(),&Buf) == 0)
-      TotalSize += Buf.st_size;
-   if (stat(userstatus.c_str(),&Buf) == 0)
-      TotalSize += Buf.st_size;
-   if (stat(status.c_str(),&Buf) != 0)
-      return _error->Errno("stat","Couldn't stat the status file %s",status.c_str());
-   TotalSize += Buf.st_size;
    
+   if (OutMap != 0)
+      *OutMap = Map.UnGuard();
    return true;
 }
 									/*}}}*/
-// MergeStatus - Add the status files to the cache			/*{{{*/
+// ComputeSize - Compute the total size of a bunch of files		/*{{{*/
 // ---------------------------------------------------------------------
-/* This adds the status files to the map */
-bool pkgMergeStatus(OpProgress &Progress,pkgCacheGenerator &Gen,
-		    unsigned long &CurrentSize,unsigned long TotalSize)
+/* Size is kind of an abstract notion that is only used for the progress
+   meter */
+static unsigned long ComputeSize(pkgIndexFile **Start,pkgIndexFile **End)
 {
-   // Grab the file names   
-   string Status[3];
-   Status[0] = _config->FindFile("Dir::State::xstatus");
-   Status[1]= _config->FindFile("Dir::State::userstatus");
-   Status[2] = _config->FindFile("Dir::State::status");
-   
-   for (int I = 0; I != 3; I++)
+   unsigned long TotalSize = 0;
+   for (; Start != End; Start++)
    {
-      // Check if the file exists and it is not the primary status file.
-      string File = Status[I];
-      if (I != 2 && FileExists(File) == false)
-	 continue;
-	 
-      FileFd Pkg(File,FileFd::ReadOnly);
-      debListParser Parser(Pkg);
-      Progress.OverallProgress(CurrentSize,TotalSize,Pkg.Size(),"Reading Package Lists");
-      if (_error->PendingError() == true)
-	 return _error->Error("Problem opening %s",File.c_str());
-      CurrentSize += Pkg.Size();
-
-      Progress.SubProgress(0,"Local Package State - " + flNotDir(File));
-      if (Gen.SelectFile(File,pkgCache::Flag::NotSource) == false)
-	 return _error->Error("Problem with SelectFile %s",File.c_str());
-      
-      if (Gen.MergeList(Parser) == false)
-	 return _error->Error("Problem with MergeList %s",File.c_str());
-      Progress.Progress(Pkg.Size());
+      if ((*Start)->HasPackages() == false)
+	 continue;      
+      TotalSize += (*Start)->Size();
    }
-   
-   return true;
+   return TotalSize;
 }
 									/*}}}*/
-// GenerateSrcCache - Write the source package lists to the map		/*{{{*/
+// BuildCache - Merge the list of index files into the cache		/*{{{*/
 // ---------------------------------------------------------------------
-/* This puts the source package cache into the given generator. */
-bool pkgGenerateSrcCache(pkgSourceList &List,OpProgress &Progress,
-			 pkgCacheGenerator &Gen,
-			 unsigned long &CurrentSize,unsigned long &TotalSize)
+/* */
+static bool BuildCache(pkgCacheGenerator &Gen,
+		       OpProgress &Progress,
+		       unsigned long &CurrentSize,unsigned long TotalSize,
+		       pkgIndexFile **Start,pkgIndexFile **End)
 {
-   string ListDir = _config->FindDir("Dir::State::lists");
-   
-   // Prepare the progress indicator
-   TotalSize = 0;
-   struct stat Buf;
-   for (pkgSourceList::const_iterator I = List.begin(); I != List.end(); I++)
-   {
-      string File = ListDir + URItoFileName(I->PackagesURI());
-      if (stat(File.c_str(),&Buf) != 0)
-	 continue;
-      TotalSize += Buf.st_size;
-   }
-   
-   if (pkgAddStatusSize(TotalSize) == false)
-      return false;
-   
-   // Generate the pkg source cache
-   CurrentSize = 0;
-   for (pkgSourceList::const_iterator I = List.begin(); I != List.end(); I++)
+   for (; Start != End; Start++)
    {
-      // Only cache deb source types.
-      if (I->Type != pkgSourceList::Item::Deb)
+      if ((*Start)->HasPackages() == false)
 	 continue;
       
-      string File = ListDir + URItoFileName(I->PackagesURI());
-      
-      if (FileExists(File) == false)
+      if ((*Start)->Exists() == false)
 	 continue;
+
+      unsigned long Size = (*Start)->Size();
+      Progress.OverallProgress(CurrentSize,TotalSize,Size,_("Reading Package Lists"));
+      CurrentSize += Size;
       
-      FileFd Pkg(File,FileFd::ReadOnly);
-      debListParser Parser(Pkg);
-      Progress.OverallProgress(CurrentSize,TotalSize,Pkg.Size(),"Reading Package Lists");
-      if (_error->PendingError() == true)
-	 return _error->Error("Problem opening %s",File.c_str());
-      CurrentSize += Pkg.Size();
-      
-      Progress.SubProgress(0,I->PackagesInfo());
-      if (Gen.SelectFile(File) == false)
-	 return _error->Error("Problem with SelectFile %s",File.c_str());
-      
-      if (Gen.MergeList(Parser) == false)
-	 return _error->Error("Problem with MergeList %s",File.c_str());
-      
-      // Check the release file
-      string RFile = ListDir + URItoFileName(I->ReleaseURI());
-      if (FileExists(RFile) == true)
-      {
-	 FileFd Rel(RFile,FileFd::ReadOnly);
-	 if (_error->PendingError() == true)
-	    return false;
-	 Parser.LoadReleaseInfo(Gen.GetCurFile(),Rel);
-      }
-   }
+      if ((*Start)->Merge(Gen,Progress) == false)
+	 return false;
+   }   
    
    return true;
 }
 									/*}}}*/
-// MakeStatusCache - Generates a cache that includes the status files	/*{{{*/
+// MakeStatusCache - Construct the status cache				/*{{{*/
 // ---------------------------------------------------------------------
-/* This copies the package source cache and then merges the status and 
-   xstatus files into it. */
-bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress)
+/* This makes sure that the status cache (the cache that has all 
+   index files from the sources list and all local ones) is ready
+   to be mmaped. If OutMap is not zero then a MMap object representing
+   the cache will be stored there. This is pretty much mandetory if you
+   are using AllowMem. AllowMem lets the function be run as non-root
+   where it builds the cache 'fast' into a memory buffer. */
+bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress,
+			MMap **OutMap,bool AllowMem)
 {
    unsigned long MapSize = _config->FindI("APT::Cache-Limit",4*1024*1024);
    
-   Progress.OverallProgress(0,1,1,"Reading Package Lists");
+   vector<pkgIndexFile *> Files(List.begin(),List.end());
+   unsigned long EndOfSource = Files.size();
+   if (_system->AddStatusFiles(Files) == false)
+      return false;
    
+   // Decide if we can write to the files..
    string CacheFile = _config->FindFile("Dir::Cache::pkgcache");
-   bool SrcOk = pkgSrcCacheCheck(List);
-   bool PkgOk = SrcOk && pkgPkgCacheCheck(CacheFile);
-
-   // Rebuild the source and package caches   
-   if (SrcOk == false)
-   {      
-      string SCacheFile = _config->FindFile("Dir::Cache::srcpkgcache");
-      FileFd SCacheF(SCacheFile,FileFd::WriteEmpty);
-      
-      /* Open the pkgcache, we want a new inode here so we do no corrupt
-       	 existing mmaps */
-      unlink(CacheFile.c_str());             
-      FileFd CacheF(CacheFile,FileFd::WriteEmpty);
-      DynamicMMap Map(CacheF,MMap::Public,MapSize);
+   string SrcCacheFile = _config->FindFile("Dir::Cache::srcpkgcache");
+   
+   // Decide if we can write to the cache
+   bool Writeable = false;
+   if (CacheFile.empty() == false)
+      Writeable = access(flNotFile(CacheFile).c_str(),W_OK) == 0;
+   else
+      if (SrcCacheFile.empty() == false)
+	 Writeable = access(flNotFile(SrcCacheFile).c_str(),W_OK) == 0;
+   
+   if (Writeable == false && AllowMem == false && CacheFile.empty() == false)
+      return _error->Error(_("Unable to write to %s"),flNotFile(CacheFile).c_str());
+   
+   Progress.OverallProgress(0,1,1,_("Reading Package Lists"));
+   
+   // Cache is OK, Fin.
+   if (CheckValidity(CacheFile,Files.begin(),Files.end(),OutMap) == true)
+   {
+      Progress.OverallProgress(1,1,1,_("Reading Package Lists"));
+      return true;
+   }
+   
+   /* At this point we know we need to reconstruct the package cache,
+      begin. */
+   SPtr<FileFd> CacheF;
+   SPtr<DynamicMMap> Map;
+   if (Writeable == true && CacheFile.empty() == false)
+   {
+      unlink(CacheFile.c_str());
+      CacheF = new FileFd(CacheFile,FileFd::WriteEmpty);
+      Map = new DynamicMMap(*CacheF,MMap::Public,MapSize);
       if (_error->PendingError() == true)
 	 return false;
-
-      pkgCacheGenerator Gen(Map,Progress);
-      unsigned long CurrentSize = 0;
-      unsigned long TotalSize = 0;
-      if (pkgGenerateSrcCache(List,Progress,Gen,CurrentSize,TotalSize) == false)
-	 return false;
-      
-      // Write the src cache
-      Gen.GetCache().HeaderP->Dirty = false;
-      if (SCacheF.Write(Map.Data(),Map.Size()) == false)
-	 return _error->Error("IO Error saving source cache");
-      Gen.GetCache().HeaderP->Dirty = true;
-      
-      // Merge in the source caches
-      return pkgMergeStatus(Progress,Gen,CurrentSize,TotalSize);
    }
-
-   if (PkgOk == true)
+   else
    {
-      Progress.OverallProgress(1,1,1,"Reading Package Lists");      
-      return true;
+      // Just build it in memory..
+      Map = new DynamicMMap(MMap::Public,MapSize);
    }
    
-   // We use the source cache to generate the package cache
-   string SCacheFile = _config->FindFile("Dir::Cache::srcpkgcache");
-   FileFd SCacheF(SCacheFile,FileFd::ReadOnly);
-   
-   /* Open the pkgcache, we want a new inode here so we do no corrupt
-      existing mmaps */
-   unlink(CacheFile.c_str());             
-   FileFd CacheF(CacheFile,FileFd::WriteEmpty);
-   DynamicMMap Map(CacheF,MMap::Public,MapSize);
-   if (_error->PendingError() == true)
-      return false;
-   
-   // Preload the map with the source cache
-   if (SCacheF.Read((unsigned char *)Map.Data() + Map.RawAllocate(SCacheF.Size()),
-		    SCacheF.Size()) == false)
-      return false;
-      
-   pkgCacheGenerator Gen(Map,Progress);
-   
-   // Compute the progress
-   unsigned long TotalSize = 0;
-   if (pkgAddStatusSize(TotalSize) == false)
-      return false;
-
+   // Lets try the source cache.
    unsigned long CurrentSize = 0;
-   return pkgMergeStatus(Progress,Gen,CurrentSize,TotalSize);
-}
-									/*}}}*/
-// MakeStatusCacheMem - Returns a map for the status cache		/*{{{*/
-// ---------------------------------------------------------------------
-/* This creates a map object for the status cache. If the process has write
-   access to the caches then it is the same as MakeStatusCache, otherwise it
-   creates a memory block and puts the cache in there. */
-MMap *pkgMakeStatusCacheMem(pkgSourceList &List,OpProgress &Progress)
-{
-   unsigned long MapSize = _config->FindI("APT::Cache-Limit",4*1024*1024);
-   
-   /* If the cache file is writeable this is just a wrapper for
-      MakeStatusCache */
-   string CacheFile = _config->FindFile("Dir::Cache::pkgcache");
-   bool Writeable = (access(CacheFile.c_str(),W_OK) == 0) ||
-                    (errno == ENOENT);
-
-   if (Writeable == true)
+   unsigned long TotalSize = 0;
+   if (CheckValidity(SrcCacheFile,Files.begin(),
+		     Files.begin()+EndOfSource) == true)
    {
-      if (pkgMakeStatusCache(List,Progress) == false)
-	 return 0;
-      
-      // Open the cache file
-      FileFd File(_config->FindFile("Dir::Cache::pkgcache"),FileFd::ReadOnly);
-      if (_error->PendingError() == true)
-	 return 0;
+      // Preload the map with the source cache
+      FileFd SCacheF(SrcCacheFile,FileFd::ReadOnly);
+      if (SCacheF.Read((unsigned char *)Map->Data() + Map->RawAllocate(SCacheF.Size()),
+		       SCacheF.Size()) == false)
+	 return false;
+
+      TotalSize = ComputeSize(Files.begin()+EndOfSource,Files.end());
       
-      MMap *Map = new MMap(File,MMap::Public | MMap::ReadOnly);
+      // Build the status cache
+      pkgCacheGenerator Gen(Map.Get(),&Progress);
       if (_error->PendingError() == true)
-      {
-	 delete Map;
-	 return 0;
-      }
-      return Map;
-   }      
-
-   // Mostly from MakeStatusCache..
-   Progress.OverallProgress(0,1,1,"Reading Package Lists");
-   
-   bool SrcOk = pkgSrcCacheCheck(List);
-   bool PkgOk = SrcOk && pkgPkgCacheCheck(CacheFile);
-			   
-   // Rebuild the source and package caches   
-   if (SrcOk == false)
+	 return false;
+      if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
+		     Files.begin()+EndOfSource,Files.end()) == false)
+	 return false;
+   }
+   else
    {
-      DynamicMMap *Map = new DynamicMMap(MMap::Public,MapSize);
-      if (_error->PendingError() == true)
-      {
-	 delete Map;
-	 return 0;
-      }
+      TotalSize = ComputeSize(Files.begin(),Files.end());
       
-      pkgCacheGenerator Gen(*Map,Progress);
-      unsigned long CurrentSize = 0;
-      unsigned long TotalSize = 0;
-      if (pkgGenerateSrcCache(List,Progress,Gen,CurrentSize,TotalSize) == false)
-      {
-	 delete Map;
-	 return 0;
-      }
+      // Build the source cache
+      pkgCacheGenerator Gen(Map.Get(),&Progress);
+      if (_error->PendingError() == true)
+	 return false;
+      if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
+		     Files.begin(),Files.begin()+EndOfSource) == false)
+	 return false;
       
-      // Merge in the source caches
-      if (pkgMergeStatus(Progress,Gen,CurrentSize,TotalSize) == false)
+      // Write it back
+      if (Writeable == true && SrcCacheFile.empty() == false)
       {
-	 delete Map;
-	 return 0;
+	 FileFd SCacheF(SrcCacheFile,FileFd::WriteEmpty);
+	 if (_error->PendingError() == true)
+	    return false;
+	 // Write out the main data
+	 if (SCacheF.Write(Map->Data(),Map->Size()) == false)
+	    return _error->Error(_("IO Error saving source cache"));
+	 SCacheF.Sync();
+	 
+	 // Write out the proper header
+	 Gen.GetCache().HeaderP->Dirty = false;
+	 if (SCacheF.Seek(0) == false ||
+	     SCacheF.Write(Map->Data(),sizeof(*Gen.GetCache().HeaderP)) == false)
+	    return _error->Error(_("IO Error saving source cache"));
+	 SCacheF.Sync();
+	 Gen.GetCache().HeaderP->Dirty = true;
       }
       
-      return Map;
+      // Build the status cache
+      if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
+		     Files.begin()+EndOfSource,Files.end()) == false)
+	 return false;
    }
 
-   if (PkgOk == true)
+   if (_error->PendingError() == true)
+      return false;
+   if (OutMap != 0)
    {
-      Progress.OverallProgress(1,1,1,"Reading Package Lists");
-      
-      // Open the cache file
-      FileFd File(_config->FindFile("Dir::Cache::pkgcache"),FileFd::ReadOnly);
-      if (_error->PendingError() == true)
-	 return 0;
-      
-      MMap *Map = new MMap(File,MMap::Public | MMap::ReadOnly);
-      if (_error->PendingError() == true)
+      if (CacheF != 0)
       {
-	 delete Map;
-	 return 0;
+	 delete Map.UnGuard();
+	 *OutMap = new MMap(*CacheF,MMap::Public | MMap::ReadOnly);
       }
-      return Map;
+      else
+      {
+	 *OutMap = Map.UnGuard();
+      }      
    }
    
-   // We use the source cache to generate the package cache
-   string SCacheFile = _config->FindFile("Dir::Cache::srcpkgcache");
-   FileFd SCacheF(SCacheFile,FileFd::ReadOnly);
-   DynamicMMap *Map = new DynamicMMap(MMap::Public,MapSize);
+   return true;
+}
+									/*}}}*/
+// MakeOnlyStatusCache - Build a cache with just the status files	/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool pkgMakeOnlyStatusCache(OpProgress &Progress,DynamicMMap **OutMap)
+{
+   unsigned long MapSize = _config->FindI("APT::Cache-Limit",4*1024*1024);
+   vector<pkgIndexFile *> Files;
+   unsigned long EndOfSource = Files.size();
+   if (_system->AddStatusFiles(Files) == false)
+      return false;
+   
+   SPtr<DynamicMMap> Map;   
+   Map = new DynamicMMap(MMap::Public,MapSize);
+   unsigned long CurrentSize = 0;
+   unsigned long TotalSize = 0;
+   
+   TotalSize = ComputeSize(Files.begin()+EndOfSource,Files.end());
+   
+   // Build the status cache
+   Progress.OverallProgress(0,1,1,_("Reading Package Lists"));
+   pkgCacheGenerator Gen(Map.Get(),&Progress);
    if (_error->PendingError() == true)
-   {
-      delete Map;
-      return 0;
-   }
+      return false;
+   if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
+		  Files.begin()+EndOfSource,Files.end()) == false)
+      return false;
    
-   // Preload the map with the source cache
-   if (SCacheF.Read((unsigned char *)Map->Data() + Map->RawAllocate(SCacheF.Size()),
-		    SCacheF.Size()) == false)
-   {
-      delete Map;
-      return 0;
-   }
-      
-   pkgCacheGenerator Gen(*Map,Progress);
+   if (_error->PendingError() == true)
+      return false;
+   *OutMap = Map.UnGuard();
    
-   // Compute the progress
-   unsigned long TotalSize = 0;
-   if (pkgAddStatusSize(TotalSize) == false)
-   {
-      delete Map;
-      return 0;
-   }
-
-   unsigned long CurrentSize = 0;
-   if (pkgMergeStatus(Progress,Gen,CurrentSize,TotalSize) == false)
-   {
-      delete Map;
-      return 0;
-   }
-    
-   return Map;
+   return true;
 }
 									/*}}}*/

+ 25 - 16
apt-pkg/pkgcachegen.h

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: pkgcachegen.h,v 1.17 1999/07/26 17:46:08 jgg Exp $
+// $Id: pkgcachegen.h,v 1.18 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
    
    Package Cache Generator - Generator for the cache structure.
@@ -16,7 +16,6 @@
    
    ##################################################################### */
 									/*}}}*/
-// Header section: pkglib
 #ifndef PKGLIB_PKGCACHEGEN_H
 #define PKGLIB_PKGCACHEGEN_H
 
@@ -29,6 +28,7 @@
 class pkgSourceList;
 class OpProgress;
 class MMap;
+class pkgIndexFile;
 
 class pkgCacheGenerator
 {
@@ -39,7 +39,7 @@ class pkgCacheGenerator
    public:
    
    class ListParser;
-   friend ListParser;
+   friend class ListParser;
    
    protected:
    
@@ -54,32 +54,28 @@ class pkgCacheGenerator
    bool NewFileVer(pkgCache::VerIterator &Ver,ListParser &List);
    unsigned long NewVersion(pkgCache::VerIterator &Ver,string VerStr,unsigned long Next);
 
+   public:
+
    unsigned long WriteUniqString(const char *S,unsigned int Size);
    inline unsigned long WriteUniqString(string S) {return WriteUniqString(S.c_str(),S.length());};
 
-   public:   
-
    void DropProgress() {Progress = 0;};
-   bool SelectFile(string File,unsigned long Flags = 0);
+   bool SelectFile(string File,string Site,pkgIndexFile const &Index,
+		   unsigned long Flags = 0);
    bool MergeList(ListParser &List,pkgCache::VerIterator *Ver = 0);
    inline pkgCache &GetCache() {return Cache;};
    inline pkgCache::PkgFileIterator GetCurFile() 
          {return pkgCache::PkgFileIterator(Cache,CurrentFile);};
       
-   pkgCacheGenerator(DynamicMMap &Map,OpProgress &Progress);
+   pkgCacheGenerator(DynamicMMap *Map,OpProgress *Progress);
    ~pkgCacheGenerator();
 };
 
-bool pkgSrcCacheCheck(pkgSourceList &List);
-bool pkgPkgCacheCheck(string CacheFile);
-bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress);
-MMap *pkgMakeStatusCacheMem(pkgSourceList &List,OpProgress &Progress);
-
 // This is the abstract package list parser class.
 class pkgCacheGenerator::ListParser
 {
    pkgCacheGenerator *Owner;
-   friend pkgCacheGenerator;
+   friend class pkgCacheGenerator;
    
    // Some cache items
    pkgCache::VerIterator OldDepVer;
@@ -113,8 +109,21 @@ class pkgCacheGenerator::ListParser
    virtual ~ListParser() {};
 };
 
-bool pkgMergeStatus(OpProgress &Progress,pkgCacheGenerator &Gen,
-		    unsigned long &CurrentSize,unsigned long TotalSize);
-bool pkgAddStatusSize(unsigned long &TotalSize);
+bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress,
+			MMap **OutMap = 0,bool AllowMem = false);
+bool pkgMakeOnlyStatusCache(OpProgress &Progress,DynamicMMap **OutMap);
+
+#ifdef APT_COMPATIBILITY
+#if APT_COMPATIBILITY != 986
+#warning "Using APT_COMPATIBILITY"
+#endif
+MMap *pkgMakeStatusCacheMem(pkgSourceList &List,OpProgress &Progress)
+{
+   MMap *Map = 0;
+   if (pkgMakeStatusCache(List,Progress,&Map,true) == false)
+      return 0;
+   return Map;
+}
+#endif
 
 #endif

+ 17 - 28
apt-pkg/pkgrecords.cc

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: pkgrecords.cc,v 1.5 1999/02/22 03:30:06 jgg Exp $
+// $Id: pkgrecords.cc,v 1.6 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
    
    Package Records - Allows access to complete package description records
@@ -13,9 +13,11 @@
 #pragma implementation "apt-pkg/pkgrecords.h"
 #endif
 #include <apt-pkg/pkgrecords.h>
-#include <apt-pkg/debrecords.h>
+#include <apt-pkg/indexfile.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/configuration.h>
+    
+#include <apti18n.h>   
 									/*}}}*/
 
 // Records::pkgRecords - Constructor					/*{{{*/
@@ -23,25 +25,21 @@
 /* This will create the necessary structures to access the status files */
 pkgRecords::pkgRecords(pkgCache &Cache) : Cache(Cache), Files(0)
 {
-   Files = new PkgFile[Cache.HeaderP->PackageFileCount];
+   Files = new Parser *[Cache.HeaderP->PackageFileCount];
+   memset(Files,0,sizeof(*Files)*Cache.HeaderP->PackageFileCount);
+   
    for (pkgCache::PkgFileIterator I = Cache.FileBegin(); 
 	I.end() == false; I++)
    {
-      // We can not initialize if the cache is out of sync.
-      if (I.IsOk() == false)
+      const pkgIndexFile::Type *Type = pkgIndexFile::Type::GetType(I.IndexType());
+      if (Type == 0)
       {
-	 _error->Error("Package file %s is out of sync.",I.FileName());
+	 _error->Error(_("Index file type '%s' is not supported"),I.IndexType());
 	 return;
       }
-   
-      // Create the file
-      Files[I->ID].File = new FileFd(I.FileName(),FileFd::ReadOnly);
-      if (_error->PendingError() == true)
-	 return;
-      
-      // Create the parser
-      Files[I->ID].Parse = new debRecordParser(*Files[I->ID].File,Cache);
-      if (_error->PendingError() == true)
+
+      Files[I->ID] = Type->CreatePkgParser(I);
+      if (Files[I->ID] == 0)
 	 return;
    }   
 }
@@ -51,6 +49,8 @@ pkgRecords::pkgRecords(pkgCache &Cache) : Cache(Cache), Files(0)
 /* */
 pkgRecords::~pkgRecords()
 {
+   for (unsigned I = 0; I != Cache.HeaderP->PackageFileCount; I++)
+      delete Files[I];
    delete [] Files;
 }
 									/*}}}*/
@@ -59,18 +59,7 @@ pkgRecords::~pkgRecords()
 /* */
 pkgRecords::Parser &pkgRecords::Lookup(pkgCache::VerFileIterator const &Ver)
 {
-   PkgFile &File = Files[Ver.File()->ID];
-   File.Parse->Jump(Ver);
-
-   return *File.Parse;
-}
-									/*}}}*/
-// Records::Pkgfile::~PkgFile - Destructor				/*{{{*/
-// ---------------------------------------------------------------------
-/* */
-pkgRecords::PkgFile::~PkgFile()
-{
-   delete Parse;
-   delete File;
+   Files[Ver.File()->ID]->Jump(Ver);
+   return *Files[Ver.File()->ID];
 }
 									/*}}}*/

+ 10 - 17
apt-pkg/pkgrecords.h

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: pkgrecords.h,v 1.4 1999/04/07 05:30:17 jgg Exp $
+// $Id: pkgrecords.h,v 1.5 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
    
    Package Records - Allows access to complete package description records
@@ -14,7 +14,6 @@
    
    ##################################################################### */
 									/*}}}*/
-// Header section: pkglib
 #ifndef PKGLIB_PKGRECORDS_H
 #define PKGLIB_PKGRECORDS_H
 
@@ -33,18 +32,8 @@ class pkgRecords
    private:
    
    pkgCache &Cache;
-   
-   // List of package files
-   struct PkgFile
-   {
-      FileFd *File;
-      Parser *Parse;
-
-      PkgFile() : File(0), Parse(0) {};
-      ~PkgFile();
-   };
-   PkgFile *Files;
-   
+   Parser **Files;
+      
    public:
 
    // Lookup function
@@ -62,18 +51,22 @@ class pkgRecords::Parser
    virtual bool Jump(pkgCache::VerFileIterator const &Ver) = 0;
    
    public:
-   friend pkgRecords;
+   friend class pkgRecords;
    
    // These refer to the archive file for the Version
    virtual string FileName() {return string();};
    virtual string MD5Hash() {return string();};
    virtual string SourcePkg() {return string();};
-   
+
    // These are some general stats about the package
    virtual string Maintainer() {return string();};
    virtual string ShortDesc() {return string();};
    virtual string LongDesc() {return string();};
-
+   virtual string Name() {return string();};
+   
+   // The record in binary form
+   virtual void GetRec(const char *&Start,const char *&Stop) {Start = Stop = 0;};
+   
    virtual ~Parser() {};
 };
 

+ 45 - 0
apt-pkg/pkgsystem.cc

@@ -0,0 +1,45 @@
+// -*- mode: cpp; mode: fold -*-
+// Description								/*{{{*/
+// $Id: pkgsystem.cc,v 1.2 2001/02/20 07:03:17 jgg Exp $
+/* ######################################################################
+
+   System - Abstraction for running on different systems.
+
+   Basic general structure..
+   
+   ##################################################################### */
+									/*}}}*/
+// Include Files							/*{{{*/
+#ifdef __GNUG__
+#pragma implementation "apt-pkg/pkgsystem.h"
+#endif
+
+#include <apt-pkg/pkgsystem.h>
+#include <apt-pkg/policy.h>
+									/*}}}*/
+
+pkgSystem *_system = 0;
+static pkgSystem *SysList[10];
+pkgSystem **pkgSystem::GlobalList = SysList;
+unsigned long pkgSystem::GlobalListLen = 0;
+
+// System::pkgSystem - Constructor					/*{{{*/
+// ---------------------------------------------------------------------
+/* Add it to the global list.. */
+pkgSystem::pkgSystem()
+{
+   SysList[GlobalListLen] = this;
+   GlobalListLen++;
+}
+									/*}}}*/
+// System::GetSystem - Get the named system				/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+pkgSystem *pkgSystem::GetSystem(const char *Label)
+{
+   for (unsigned I = 0; I != GlobalListLen; I++)
+      if (strcmp(SysList[I]->Label,Label) == 0)
+	 return SysList[I];
+   return 0;   
+}
+									/*}}}*/

+ 95 - 0
apt-pkg/pkgsystem.h

@@ -0,0 +1,95 @@
+// -*- mode: cpp; mode: fold -*-
+// Description								/*{{{*/
+// $Id: pkgsystem.h,v 1.2 2001/02/20 07:03:17 jgg Exp $
+/* ######################################################################
+
+   System - Abstraction for running on different systems.
+   
+   Instances of this class can be thought of as factories or meta-classes
+   for a variety of more specialized classes. Together this class and 
+   it's speciallized offspring completely define the environment and how
+   to access resources for a specific system. There are several sub
+   areas that are all orthogonal - each system has a unique combination of
+   these sub areas:
+       - Versioning. Different systems have different ideas on versions.
+         Within a system all sub classes must follow the same versioning 
+         rules.
+       - Local tool locking to prevent multiple tools from accessing the
+         same database.
+       - Candidate Version selection policy - this is probably almost always
+         managed using a standard APT class
+       - Actual Package installation 
+         * Indication of what kind of binary formats are supported
+       - Selection of local 'status' indexes that make up the pkgCache.
+      
+   It is important to note that the handling of index files is not a 
+   function of the system. Index files are handled through a seperate 
+   abstraction - the only requirement is that the index files have the
+   same idea of versioning as the target system.
+   
+   Upon startup each supported system instantiates an instance of the
+   pkgSystem class (using a global constructor) which will make itself
+   available to the main APT init routine. That routine will select the
+   proper system and make it the global default.
+   
+   ##################################################################### */
+									/*}}}*/
+#ifndef PKGLIB_PKGSYSTEM_H
+#define PKGLIB_PKGSYSTEM_H
+
+#ifdef __GNUG__
+#pragma interface "apt-pkg/pkgsystem.h"
+#endif
+
+#include <apt-pkg/depcache.h>
+#include <vector.h>
+    
+class pkgPackageManager;
+class pkgVersioningSystem;
+class Configuration;
+class pkgIndexFile;
+
+class pkgSystem
+{   
+   public:
+
+   // Global list of supported systems
+   static pkgSystem **GlobalList;
+   static unsigned long GlobalListLen;
+   static pkgSystem *GetSystem(const char *Label);
+   
+   const char *Label;
+   pkgVersioningSystem *VS;
+   
+   /* Prevent other programs from touching shared data not covered by
+      other locks (cache or state locks) */
+   virtual bool Lock() = 0;
+   virtual bool UnLock(bool NoErrors = false) = 0;
+   
+   /* Various helper classes to interface with specific bits of this
+      environment */
+   virtual pkgPackageManager *CreatePM(pkgDepCache *Cache) const = 0;
+
+   /* Load environment specific configuration and perform any other setup
+      necessary */
+   virtual bool Initialize(Configuration &Cnf) {return true;};
+   
+   /* Type is some kind of Globally Unique way of differentiating
+      archive file types.. */
+   virtual bool ArchiveSupported(const char *Type) = 0;
+
+   // Return a list of system index files..
+   virtual bool AddStatusFiles(vector<pkgIndexFile *> &List) = 0;   
+   
+   /* Evauluate how 'right' we are for this system based on the filesystem
+      etc.. */
+   virtual signed Score(Configuration const &Cnf) {return 0;};
+   
+   pkgSystem();
+   virtual ~pkgSystem() {};
+};
+
+// The environment we are operating in.
+extern pkgSystem *_system;
+
+#endif

+ 275 - 0
apt-pkg/policy.cc

@@ -0,0 +1,275 @@
+// -*- mode: cpp; mode: fold -*-
+// Description								/*{{{*/
+// $Id: policy.cc,v 1.2 2001/02/20 07:03:17 jgg Exp $
+/* ######################################################################
+
+   Package Version Policy implementation
+   
+   This is just a really simple wrapper around pkgVersionMatch with
+   some added goodies to manage the list of things..
+   
+   Priority Table:
+   
+   1000 -> inf = Downgradeable priorities
+   1000        = The 'no downgrade' pseduo-status file
+   100 -> 1000 = Standard priorities
+   990         = Config file override package files
+   989         = Start for preference auto-priorities
+   500         = Default package files
+   100         = The status file
+   0 -> 100    = NotAutomatic sources like experimental
+   -inf -> 0   = Never selected   
+   
+   ##################################################################### */
+									/*}}}*/
+// Include Files							/*{{{*/
+#ifdef __GNUG__
+#pragma implementation "apt-pkg/policy.h"
+#endif
+#include <apt-pkg/policy.h>
+#include <apt-pkg/configuration.h>
+#include <apt-pkg/tagfile.h>
+#include <apt-pkg/strutl.h>
+#include <apt-pkg/error.h>
+#include <apt-pkg/sptr.h>
+    
+#include <apti18n.h>
+									/*}}}*/
+
+// Policy::Init - Startup and bind to a cache				/*{{{*/
+// ---------------------------------------------------------------------
+/* Set the defaults for operation. The default mode with no loaded policy
+   file matches the V0 policy engine. */
+pkgPolicy::pkgPolicy(pkgCache *Owner) : Pins(0), PFPriority(0), Cache(Owner)
+{
+   PFPriority = new signed short[Owner->Head().PackageFileCount];
+   Pins = new Pin[Owner->Head().PackageCount];
+
+   for (unsigned long I = 0; I != Owner->Head().PackageCount; I++)
+      Pins[I].Type = pkgVersionMatch::None;
+
+   // The config file has a master override.
+   string DefRel = _config->Find("APT::Default-Release");
+   if (DefRel.empty() == false)
+      CreatePin(pkgVersionMatch::Release,"",DefRel,990);
+      
+   InitDefaults();
+}
+									/*}}}*/
+// Policy::InitDefaults - Compute the default selections		/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool pkgPolicy::InitDefaults()
+{   
+   // Initialize the priorities based on the status of the package file
+   for (pkgCache::PkgFileIterator I = Cache->FileBegin(); I != Cache->FileEnd(); I++)
+   {
+      PFPriority[I->ID] = 500;
+      if ((I->Flags & pkgCache::Flag::NotSource) == pkgCache::Flag::NotSource)
+	 PFPriority[I->ID] = 100;
+      else
+	 if ((I->Flags & pkgCache::Flag::NotAutomatic) == pkgCache::Flag::NotAutomatic)
+	    PFPriority[I->ID] = 1;
+   }
+
+   // Apply the defaults..
+   SPtr<bool> Fixed = new bool[Cache->HeaderP->PackageFileCount];
+   memset(Fixed,0,sizeof(*Fixed)*Cache->HeaderP->PackageFileCount);
+   signed Cur = 989;
+   StatusOverride = false;
+   for (vector<Pin>::const_iterator I = Defaults.begin(); I != Defaults.end();
+	I++, Cur--)
+   {
+      pkgVersionMatch Match(I->Data,I->Type);
+      for (pkgCache::PkgFileIterator F = Cache->FileBegin(); F != Cache->FileEnd(); F++)
+      {
+/* hmm?
+ if ((F->Flags & pkgCache::Flag::NotSource) == pkgCache::Flag::NotSource)
+	    continue;*/
+
+	 if (Match.FileMatch(F) == true && Fixed[F->ID] == false)
+	 {
+	    if (I->Priority != 0 && I->Priority > 0)
+	       Cur = I->Priority;
+	    
+	    if (I->Priority < 0)
+	       PFPriority[F->ID] =  I->Priority;
+	    else
+	       PFPriority[F->ID] = Cur;
+	    
+	    if (PFPriority[F->ID] > 1000)
+	       StatusOverride = true;
+	    
+	    Fixed[F->ID] = true;
+	 }      
+      }      
+   }
+
+   if (_config->FindB("Debug::pkgPolicy",false) == true)
+      for (pkgCache::PkgFileIterator F = Cache->FileBegin(); F != Cache->FileEnd(); F++)
+	 cout << "Prio of " << F.FileName() << ' ' << PFPriority[F->ID] << endl; 
+   
+   return true;   
+}
+									/*}}}*/
+// Policy::GetCandidateVer - Get the candidate install version		/*{{{*/
+// ---------------------------------------------------------------------
+/* Evaluate the package pins and the default list to deteremine what the
+   best package is. */
+pkgCache::VerIterator pkgPolicy::GetCandidateVer(pkgCache::PkgIterator Pkg)
+{
+   const Pin &PPkg = Pins[Pkg->ID];
+   
+   // Look for a package pin and evaluate it.
+   signed Max = 0;
+   pkgCache::VerIterator Pref(*Cache);
+   if (PPkg.Type != pkgVersionMatch::None)
+   {
+      pkgVersionMatch Match(PPkg.Data,PPkg.Type);
+      Pref = Match.Find(Pkg);
+      Max = PPkg.Priority;
+      if (PPkg.Priority == 0)
+	 Max = 989;
+   }
+      
+   /* Falling through to the default version.. Setting Max to zero
+      effectively excludes everything <= 0 which are the non-automatic
+      priorities.. The status file is given a prio of 100 which will exclude
+      not-automatic sources, except in a single shot not-installed mode.
+      The second pseduo-status file is at prio 1000, above which will permit
+      the user to force-downgrade things.
+      
+      The user pin is subject to the same priority rules as default 
+      selections. Thus there are two ways to create a pin - a pin that
+      tracks the default when the default is taken away, and a permanent
+      pin that stays at that setting.
+    */
+   for (pkgCache::VerIterator Ver = Pkg.VersionList(); Ver.end() == false; Ver++)
+   {      
+      for (pkgCache::VerFileIterator VF = Ver.FileList(); VF.end() == false; VF++)
+      {
+	 signed Prio = PFPriority[VF.File()->ID];
+	 if (Prio > Max)
+	 {
+	    Pref = Ver;
+	    Max = Prio;
+	 }	 
+      }      
+      
+      if (Pkg.CurrentVer() == Ver && Max < 1000)
+      {
+	 /* Elevate our current selection (or the status file itself)
+	    to the Pseudo-status priority. */
+	 if (Pref.end() == true)
+	    Pref = Ver;
+	 Max = 1000;
+	 
+	 // Fast path optimize.
+	 if (StatusOverride == false)
+	    break;
+      }            
+   }
+   
+   return Pref;
+}
+									/*}}}*/
+// Policy::CreatePin - Create an entry in the pin table..		/*{{{*/
+// ---------------------------------------------------------------------
+/* For performance we have 3 tables, the default table, the main cache
+   table (hashed to the cache). A blank package name indicates the pin
+   belongs to the default table. Order of insertion matters here, the
+   earlier defaults override later ones. */
+void pkgPolicy::CreatePin(pkgVersionMatch::MatchType Type,string Name,
+			  string Data,signed short Priority)
+{
+   pkgCache::PkgIterator Pkg = Cache->FindPkg(Name);
+   Pin *P = 0;
+   
+   if (Name.empty() == true)
+      P = Defaults.insert(Defaults.end());
+   else
+   {
+      // Get a spot to put the pin
+      if (Pkg.end() == true)
+      {
+	 // Check the unmatched table
+	 for (vector<PkgPin>::iterator I = Unmatched.begin(); 
+	      I != Unmatched.end() && P == 0; I++)
+	    if (I->Pkg == Name)
+	       P = I;
+	 
+	 if (P == 0)
+	    P = Unmatched.insert(Unmatched.end());      
+      }
+      else
+      {
+	 P = Pins + Pkg->ID;
+      }      
+   }
+   
+   // Set..
+   P->Type = Type;
+   P->Priority = Priority;
+   P->Data = Data;
+}
+									/*}}}*/
+
+// ReadPinFile - Load the pin file into a Policy			/*{{{*/
+// ---------------------------------------------------------------------
+/* I'd like to see the preferences file store more than just pin information
+   but right now that is the only stuff I have to store. Later there will
+   have to be some kind of combined super parser to get the data into all
+   the right classes.. */
+bool ReadPinFile(pkgPolicy &Plcy,string File)
+{
+   if (File.empty() == true)
+      File = _config->FindFile("Dir::Etc::Preferences");
+
+   if (FileExists(File) == false)
+      return true;
+   
+   FileFd Fd(File,FileFd::ReadOnly);
+   pkgTagFile TF(&Fd);
+   if (_error->PendingError() == true)
+      return false;
+   
+   pkgTagSection Tags;
+   while (TF.Step(Tags) == true)
+   {
+      string Name = Tags.FindS("Package");
+      if (Name.empty() == true)
+	 return _error->Error(_("Invalid record in the preferences file, no Package header"));
+      if (Name == "*")
+	 Name = string();
+      
+      const char *Start;
+      const char *End;
+      if (Tags.Find("Pin",Start,End) == false)
+	 continue;
+	 
+      const char *Word = Start;
+      for (; Word != End && isspace(*Word) == 0; Word++);
+
+      // Parse the type..
+      pkgVersionMatch::MatchType Type;
+      if (stringcasecmp(Start,Word,"version") == 0 && Name.empty() == false)
+	 Type = pkgVersionMatch::Version;
+      else if (stringcasecmp(Start,Word,"release") == 0)
+	 Type = pkgVersionMatch::Release;
+      else if (stringcasecmp(Start,Word,"origin") == 0)
+	 Type = pkgVersionMatch::Origin;
+      else
+      {
+	 _error->Warning(_("Did not understand pin type %s"),string(Start,Word).c_str());
+	 continue;
+      }
+      for (; Word != End && isspace(*Word) != 0; Word++);
+
+      Plcy.CreatePin(Type,Name,string(Word,End),
+		     Tags.FindI("Pin-Priority"));
+   }
+
+   Plcy.InitDefaults();
+   return true;
+}
+									/*}}}*/

+ 83 - 0
apt-pkg/policy.h

@@ -0,0 +1,83 @@
+// -*- mode: cpp; mode: fold -*-
+// Description								/*{{{*/
+// $Id: policy.h,v 1.2 2001/02/20 07:03:17 jgg Exp $
+/* ######################################################################
+
+   Package Version Policy implementation
+
+   This implements the more advanced 'Version 4' APT policy engine. The
+   standard 'Version 0' engine is included inside the DepCache which is
+   it's historical location.
+   
+   The V4 engine allows the user to completly control all aspects of
+   version selection. There are three primary means to choose a version
+    * Selection by version match
+    * Selection by Release file match
+    * Selection by origin server
+   
+   Each package may be 'pinned' with a single criteria, which will ultimately
+   result in the selection of a single version, or no version, for each
+   package.
+   
+   Furthermore, the default selection can be influenced by specifying
+   the ordering of package files. The order is derived by reading the
+   package file preferences and assigning a priority to each package 
+   file.
+   
+   A special flag may be set to indicate if no version should be returned
+   if no matching versions are found, otherwise the default matching
+   rules are used to locate a hit.
+   
+   ##################################################################### */
+									/*}}}*/
+#ifndef PKGLIB_POLICY_H
+#define PKGLIB_POLICY_H
+
+#ifdef __GNUG__
+#pragma interface "apt-pkg/policy.h"
+#endif
+
+#include <apt-pkg/depcache.h>
+#include <apt-pkg/versionmatch.h>
+#include <vector>
+
+class pkgPolicy : public pkgDepCache::Policy
+{
+   struct Pin
+   {
+      pkgVersionMatch::MatchType Type;
+      string Data;
+      signed short Priority;
+      Pin() : Type(pkgVersionMatch::None), Priority(0) {};
+   };
+
+   struct PkgPin : Pin
+   {
+      string Pkg;
+   };
+   
+   protected:
+   
+   Pin *Pins;
+   signed short *PFPriority;
+   vector<Pin> Defaults;
+   vector<PkgPin> Unmatched;
+   pkgCache *Cache;
+   bool StatusOverride;
+   
+   public:
+
+   void CreatePin(pkgVersionMatch::MatchType Type,string Pkg,
+		  string Data,signed short Priority);
+   
+   virtual pkgCache::VerIterator GetCandidateVer(pkgCache::PkgIterator Pkg);
+   virtual bool IsImportantDep(pkgCache::DepIterator Dep) {return pkgDepCache::Policy::IsImportantDep(Dep);};
+   bool InitDefaults();
+   
+   pkgPolicy(pkgCache *Owner);
+   virtual ~pkgPolicy() {delete [] PFPriority; delete [] Pins;};
+};
+
+bool ReadPinFile(pkgPolicy &Plcy,string File = "");
+
+#endif

+ 127 - 297
apt-pkg/sourcelist.cc

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: sourcelist.cc,v 1.17 1999/10/17 07:30:23 jgg Exp $
+// $Id: sourcelist.cc,v 1.18 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
 
    List of Sources
@@ -18,10 +18,99 @@
 #include <apt-pkg/configuration.h>
 #include <apt-pkg/strutl.h>
 
+#include <apti18n.h>
+
 #include <fstream.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/stat.h>
+									/*}}}*/
+
+// Global list of Item supported
+static  pkgSourceList::Type *ItmList[10];
+pkgSourceList::Type **pkgSourceList::Type::GlobalList = ItmList;
+unsigned long pkgSourceList::Type::GlobalListLen = 0;
+
+// Type::Type - Constructor						/*{{{*/
+// ---------------------------------------------------------------------
+/* Link this to the global list of items*/
+pkgSourceList::Type::Type()
+{
+   ItmList[GlobalListLen] = this;
+   GlobalListLen++;
+}
+									/*}}}*/
+// Type::GetType - Get a specific meta for a given type			/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+pkgSourceList::Type *pkgSourceList::Type::GetType(const char *Type)
+{
+   for (unsigned I = 0; I != GlobalListLen; I++)
+      if (strcmp(GlobalList[I]->Name,Type) == 0)
+	 return GlobalList[I];
+   return 0;
+}
+									/*}}}*/
+// Type::FixupURI - Normalize the URI and check it..			/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool pkgSourceList::Type::FixupURI(string &URI) const
+{
+   if (URI.empty() == true)
+      return false;
+
+   if (URI.find(':') == string::npos)
+      return false;
+
+   URI = SubstVar(URI,"$(ARCH)",_config->Find("APT::Architecture"));
+   
+   // Make sure that the URN is / postfixed
+   if (URI[URI.size() - 1] != '/')
+      URI += '/';
+   
+   return true;
+}
+									/*}}}*/
+// Type::ParseLine - Parse a single line				/*{{{*/
+// ---------------------------------------------------------------------
+/* This is a generic one that is the 'usual' format for sources.list
+   Weird types may override this. */
+bool pkgSourceList::Type::ParseLine(vector<pkgIndexFile *> &List,
+				    const char *Buffer,
+				    unsigned long CurLine,
+				    string File) const
+{
+   string URI;
+   string Dist;
+   string Section;   
+   
+   if (ParseQuoteWord(Buffer,URI) == false)
+      return _error->Error(_("Malformed line %lu in source list %s (URI)"),CurLine,File.c_str());
+   if (ParseQuoteWord(Buffer,Dist) == false)
+      return _error->Error(_("Malformed line %lu in source list %s (dist)"),CurLine,File.c_str());
+      
+   if (FixupURI(URI) == false)
+      return _error->Error(_("Malformed line %lu in source list %s (URI parse)"),CurLine,File.c_str());
+   
+   // Check for an absolute dists specification.
+   if (Dist.empty() == false && Dist[Dist.size() - 1] == '/')
+   {
+      if (ParseQuoteWord(Buffer,Section) == true)
+	 return _error->Error(_("Malformed line %lu in source list %s (Absolute dist)"),CurLine,File.c_str());
+      Dist = SubstVar(Dist,"$(ARCH)",_config->Find("APT::Architecture"));
+      return CreateItem(List,URI,Dist,Section);
+   }
+   
+   // Grab the rest of the dists
+   if (ParseQuoteWord(Buffer,Section) == false)
+      return _error->Error(_("Malformed line %lu in source list %s (dist parse)"),CurLine,File.c_str());
+   
+   do
+   {
+      if (CreateItem(List,URI,Dist,Section) == false)
+	 return false;
+   }
+   while (ParseQuoteWord(Buffer,Section) == true);
+   
+   return true;
+}
 									/*}}}*/
 
 // SourceList::pkgSourceList - Constructors				/*{{{*/
@@ -52,7 +141,7 @@ 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());
+      return _error->Errno("ifstream::ifstream",_("Opening %s"),File.c_str());
    
    List.erase(List.begin(),List.end());
    char Buffer[300];
@@ -63,318 +152,59 @@ bool pkgSourceList::Read(string File)
       F.getline(Buffer,sizeof(Buffer));
       CurLine++;
       _strtabexpand(Buffer,sizeof(Buffer));
-      _strstrip(Buffer);
+      
+      
+      char *I;
+      for (I = Buffer; *I != 0 && *I != '#'; I++);
+      *I = 0;
+      
+      const char *C = _strstrip(Buffer);
       
       // Comment or blank
-      if (Buffer[0] == '#' || Buffer[0] == 0)
+      if (C[0] == '#' || C[0] == 0)
 	 continue;
-      
+      	    
       // Grok it
-      string Type;
-      string URI;
-      Item Itm;
-      const 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)",_config->Find("APT::Architecture"));
-	 List.push_back(Itm);
-	 continue;
-      }
+      string LineType;
+      if (ParseQuoteWord(C,LineType) == false)
+	 return _error->Error(_("Malformed line %u in source list %s (type)"),CurLine,File.c_str());
 
-      // 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());
+      Type *Parse = Type::GetType(LineType.c_str());
+      if (Parse == 0)
+	 return _error->Error(_("Type '%s' is not known in on line %u in source list %s"),LineType.c_str(),CurLine,File.c_str());
       
-      do
-      {
-	 List.push_back(Itm);
-      }
-      while (ParseQuoteWord(C,Itm.Section) == true);
+      if (Parse->ParseLine(List,C,CurLine,File) == false)
+	 return false;
    }
    return true;
 }
 									/*}}}*/
-// 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 << (int)Itm.Type << ' ' << Itm.URI << ' ' << Itm.Dist << ' ' << Itm.Section;
-   return O;
-}
-									/*}}}*/
-// SourceList::Item::SetType - Sets the distribution type		/*{{{*/
+// SourceList::FindIndex - Get the index associated with a file		/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-bool pkgSourceList::Item::SetType(string S)
+bool pkgSourceList::FindIndex(pkgCache::PkgFileIterator File,
+			      pkgIndexFile *&Found) const
 {
-   if (S == "deb")
+   for (const_iterator I = List.begin(); I != List.end(); I++)
    {
-      Type = Deb;
-      return true;
-   }
-
-   if (S == "deb-src")
-   {
-      Type = DebSrc;
-      return true;
+      if ((*I)->FindInCache(*File.Cache()) == File)
+      {
+	 Found = *I;
+	 return true;
+      }
    }
-
-   return false;
-}
-									/*}}}*/
-// 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)",_config->Find("APT::Architecture"));
    
-   // 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] == '/')
-      {
-	 if (Dist != "/")
-	    Res = URI + Dist;
-	 else 
-	    Res = URI;
-      }      
-      else
-	 Res = URI + "dists/" + Dist + '/' + Section +
-	 "/binary-" + _config->Find("APT::Architecture") + '/';
-      
-      Res += "Packages";
-      break;
-      
-      case DebSrc:
-      if (Dist[Dist.size() - 1] == '/')
-	 Res = URI + Dist;
-      else
-	 Res = URI + "dists/" + Dist + '/' + Section +
-	 "/source/";
-      
-      Res += "Sources";
-      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] == '/')
-      {
-	 if (Dist != "/")
-	    Res += Dist;
-      }      
-      else
-	 Res += Dist + '/' + Section;
-      
-      Res += " Packages";
-      break;
-     
-      case DebSrc:
-      Res += SiteOnly(URI) + ' ';
-      if (Dist[Dist.size() - 1] == '/')
-	 Res += Dist;
-      else
-	 Res += Dist + '/' + Section;
-      
-      Res += " Sources";
-      break;
-   };
-   return Res;
-}
-									/*}}}*/
-// SourceList::Item::ReleaseURI - Returns a URI to the release file	/*{{{*/
-// ---------------------------------------------------------------------
-/* */
-string pkgSourceList::Item::ReleaseURI() const
-{
-   string Res;
-   switch (Type)
-   {
-      case Deb:
-      if (Dist[Dist.size() - 1] == '/')
-      {
-	 if (Dist != "/")
-	    Res = URI + Dist;
-	 else
-	    Res = URI;
-      }      
-      else
-	 Res = URI + "dists/" + Dist + '/' + Section +
-	 "/binary-" + _config->Find("APT::Architecture") + '/';
-      
-      Res += "Release";
-      break;
-      
-      case DebSrc:
-      if (Dist[Dist.size() - 1] == '/')
-	 Res = URI + Dist;
-      else
-	 Res = URI + "dists/" + Dist + '/' + Section +
-	 "/source/";
-      
-      Res += "Release";
-      break;
-   };
-   return Res;
-}
-									/*}}}*/
-// SourceList::Item::ReleaseInfo - Shorter version of the URI		/*{{{*/
-// ---------------------------------------------------------------------
-/* This is a shorter version that is designed to be < 60 chars or so */
-string pkgSourceList::Item::ReleaseInfo() const
-{
-   string Res;
-   switch (Type)
-   {
-      case Deb:
-      case DebSrc:
-      Res += SiteOnly(URI) + ' ';
-      if (Dist[Dist.size() - 1] == '/')
-      {
-	 if (Dist != "/")
-	    Res += Dist;
-      }      
-      else
-	 Res += Dist + '/' + Section;
-      
-      Res += " Release";
-      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 DebSrc:
-      case Deb:
-      Res += SiteOnly(URI) + ' ';
-      if (Dist[Dist.size() - 1] == '/')
-      {
-	 if (Dist != "/")
-	    Res += Dist;
-      }      
-      else
-	 Res += Dist + '/' + Section;
-      
-      Res += " ";
-      Res += Ver.ParentPkg().Name();
-      Res += " ";
-      Res += Ver.VerStr();
-      
-      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:
-      case DebSrc:
-      Res = URI + File;
-      break;
-   };
-   return Res;
-}
-									/*}}}*/
-// SourceList::Item::SourceInfo	- Returns an info line for a source	/*{{{*/
-// ---------------------------------------------------------------------
-/* */
-string pkgSourceList::Item::SourceInfo(string Pkg,string Ver,string Comp) const
-{
-   string Res;
-   switch (Type)
-   {
-      case DebSrc:
-      case Deb:
-      Res += SiteOnly(URI) + ' ';
-      if (Dist[Dist.size() - 1] == '/')
-      {
-	 if (Dist != "/")
-	    Res += Dist;
-      }      
-      else
-	 Res += Dist + '/' + Section;
-      
-      Res += " ";
-      Res += Pkg;
-      Res += " ";
-      Res += Ver;
-      if (Comp.empty() == false)
-	 Res += " (" + Comp + ")";
-      break;
-   };
-   return Res;
+   return false;
 }
 									/*}}}*/
-// SourceList::Item::SiteOnly - Strip off the path part of a URI	/*{{{*/
+// SourceList::GetIndexes - Load the index files into the downloader	/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-string pkgSourceList::Item::SiteOnly(string URI) const
+bool pkgSourceList::GetIndexes(pkgAcquire *Owner) const
 {
-   ::URI U(URI);
-   U.User = string();
-   U.Password = string();
-   U.Path = string();
-   U.Port = 0;
-   return U;
+   for (const_iterator I = List.begin(); I != List.end(); I++)
+      if ((*I)->GetIndexes(Owner) == false)
+	 return false;
+   return true;
 }
 									/*}}}*/

+ 35 - 26
apt-pkg/sourcelist.h

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: sourcelist.h,v 1.8 1999/04/07 05:30:18 jgg Exp $
+// $Id: sourcelist.h,v 1.9 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
 
    SourceList - Manage a list of sources
@@ -12,18 +12,22 @@
    All sources have a type associated with them that defines the layout
    of the archive. The exact format of the file is documented in
    files.sgml.
+
+   The types are mapped through a list of type definitions which handle
+   the actual construction of the type. After loading a source list all
+   you have is a list of package index files that have the ability
+   to be Acquired.
    
    ##################################################################### */
 									/*}}}*/
-// Header section: pkglib
 #ifndef PKGLIB_SOURCELIST_H
 #define PKGLIB_SOURCELIST_H
 
 #include <string>
 #include <vector>
-#include <iostream.h>
 #include <apt-pkg/pkgcache.h>
-
+#include <apt-pkg/indexfile.h>
+    
 #ifdef __GNUG__
 #pragma interface "apt-pkg/sourcelist.h"
 #endif
@@ -33,32 +37,35 @@ class pkgSourceList
 {
    public:
    
-   /* Each item in the source list, each line can have more than one
-      item */
-   struct Item
+   // List of supported source list types
+   class Type
    {
-      enum {Deb, DebSrc} Type;
-
-      string URI;
-      string Dist;
-      string Section;
+      public:
       
-      bool SetType(string S);
-      bool SetURI(string S);
-      string PackagesURI() const;
-      string PackagesInfo() const;      
-      string ReleaseURI() const;
-      string ReleaseInfo() const;
-      string SourceInfo(string Pkg,string Ver,string Comp) const;
-      string SiteOnly(string URI) const;
-      string ArchiveInfo(pkgCache::VerIterator Ver) const;
-      string ArchiveURI(string File) const;
+      // Global list of Items supported
+      static Type **GlobalList;
+      static unsigned long GlobalListLen;
+      static Type *GetType(const char *Type);
+
+      const char *Name;
+      const char *Label;
+
+      bool FixupURI(string &URI) const;
+      virtual bool ParseLine(vector<pkgIndexFile *> &List,
+			     const char *Buffer,
+			     unsigned long CurLine,string File) const;
+      virtual bool CreateItem(vector<pkgIndexFile *> &List,string URI,
+			      string Dist,string Section) const = 0;
+			      
+      Type();
+      virtual ~Type() {};
    };
-   typedef vector<Item>::const_iterator const_iterator;
+   
+   typedef vector<pkgIndexFile *>::const_iterator const_iterator;
    
    protected:
    
-   vector<Item> List;
+   vector<pkgIndexFile *> List;
    
    public:
 
@@ -71,10 +78,12 @@ class pkgSourceList
    inline unsigned int size() const {return List.size();};
    inline bool empty() const {return List.empty();};
 
+   bool FindIndex(pkgCache::PkgFileIterator File,
+		  pkgIndexFile *&Found) const;
+   bool GetIndexes(pkgAcquire *Owner) const;
+   
    pkgSourceList();
    pkgSourceList(string File);   
 };
 
-ostream &operator <<(ostream &O,pkgSourceList::Item &Itm);
-
 #endif

+ 34 - 34
apt-pkg/srcrecords.cc

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: srcrecords.cc,v 1.3 1999/10/18 04:15:24 jgg Exp $
+// $Id: srcrecords.cc,v 1.4 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
    
    Source Package Records - Allows access to source package records
@@ -17,9 +17,10 @@
 
 #include <apt-pkg/srcrecords.h>
 #include <apt-pkg/error.h>
-#include <apt-pkg/configuration.h>
+#include <apt-pkg/sourcelist.h>
 #include <apt-pkg/strutl.h>
-#include <apt-pkg/debsrcrecords.h>
+    
+#include <apti18n.h>    
 									/*}}}*/
 
 // SrcRecords::pkgSrcRecords - Constructor				/*{{{*/
@@ -27,46 +28,28 @@
 /* Open all the source index files */
 pkgSrcRecords::pkgSrcRecords(pkgSourceList &List) : Files(0), Current(0)
 {
-   pkgSourceList::const_iterator I = List.begin();
-   
-   // Count how many items we will need
+   Files = new Parser *[List.end() - List.begin() + 1];
+	  
    unsigned int Count = 0;
+   pkgSourceList::const_iterator I = List.begin();
    for (; I != List.end(); I++)
-      if (I->Type == pkgSourceList::Item::DebSrc)
+   {
+      Files[Count] = (*I)->CreateSrcParser();
+      if (_error->PendingError() == true)
+	 return;
+      if (Files[Count] != 0)
 	 Count++;
-
+   }
+   Files[Count] = 0;
+   
    // Doesnt work without any source index files
    if (Count == 0)
    {
-      _error->Error("Sorry, you must put some 'source' uris"
-		    " in your sources.list");
+      _error->Error(_("Sorry, you must put some 'source' URIs"
+		    " in your sources.list"));
       return;
    }   
 
-   Files = new Parser *[Count+1];
-   memset(Files,0,sizeof(*Files)*(Count+1));
-   
-   // Create the parser objects
-   Count = 0;
-   string Dir = _config->FindDir("Dir::State::lists");
-   for (I = List.begin(); I != List.end(); I++)
-   {
-      if (I->Type != pkgSourceList::Item::DebSrc)
-	 continue;
-
-      // Open the file
-      FileFd *FD = new FileFd(Dir + URItoFileName(I->PackagesURI()),
-			      FileFd::ReadOnly);
-      if (_error->PendingError() == true)
-      {
-	 delete FD;
-	 return;
-      }
-      
-      Files[Count] = new debSrcRecordParser(FD,I);
-      Count++;
-   }
-
    Restart();
 }
 									/*}}}*/
@@ -81,6 +64,7 @@ pkgSrcRecords::~pkgSrcRecords()
    // Blow away all the parser objects
    for (unsigned int Count = 0; Files[Count] != 0; Count++)
       delete Files[Count];
+   delete [] Files;
 }
 									/*}}}*/
 // SrcRecords::Restart - Restart the search				/*{{{*/
@@ -136,4 +120,20 @@ pkgSrcRecords::Parser *pkgSrcRecords::Find(const char *Package,bool SrcOnly)
    }
 }
 									/*}}}*/
+// Parser::BuildDepType - Convert a build dep to a string		/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+const char *pkgSrcRecords::Parser::BuildDepType(unsigned char Type)
+{
+   const char *fields[] = {"Build-Depends", 
+                           "Build-Depends-Indep",
+			   "Build-Conflicts",
+			   "Build-Conflicts-Indep"};
+   if (Type < 4) 
+      return fields[Type]; 
+   else 
+      return "";
+}
+									/*}}}*/
+
 

+ 32 - 15
apt-pkg/srcrecords.h

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: srcrecords.h,v 1.5 1999/10/18 03:44:39 jgg Exp $
+// $Id: srcrecords.h,v 1.6 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
    
    Source Package Records - Allows access to source package records
@@ -17,9 +17,11 @@
 #pragma interface "apt-pkg/srcrecords.h"
 #endif 
 
-#include <apt-pkg/fileutl.h>
-#include <apt-pkg/sourcelist.h>
+#include <string>
+#include <vector>    
 
+class pkgSourceList;
+class pkgIndexFile;
 class pkgSrcRecords
 {
    public:
@@ -30,17 +32,30 @@ class pkgSrcRecords
       string MD5Hash;
       unsigned long Size;
       string Path;
+      string Type;
    };
    
    // Abstract parser for each source record
    class Parser
    {
-      FileFd *File;
-      pkgSourceList::const_iterator SrcItem;
+      protected:
+      
+      const pkgIndexFile *iIndex;
       
       public:
 
-      inline pkgSourceList::const_iterator Source() const {return SrcItem;};
+      enum BuildDep {BuildDepend=0x0,BuildDependIndep=0x1,
+	             BuildConflict=0x2,BuildConflictIndep=0x3};
+
+      struct BuildDepRec 
+      {
+         string Package;
+	 string Version;
+	 unsigned int Op;
+	 unsigned char Type;
+      };
+	
+      inline const pkgIndexFile &Index() const {return *iIndex;};
       
       virtual bool Restart() = 0;
       virtual bool Step() = 0;
@@ -48,16 +63,19 @@ class pkgSrcRecords
       virtual unsigned long Offset() = 0;
       virtual string AsStr() = 0;
       
-      virtual string Package() = 0;
-      virtual string Version() = 0;
-      virtual string Maintainer() = 0;
-      virtual string Section() = 0;
-      virtual const char **Binaries() = 0;
+      virtual string Package() const = 0;
+      virtual string Version() const = 0;
+      virtual string Maintainer() const = 0;
+      virtual string Section() const = 0;
+      virtual const char **Binaries() = 0;   // Ownership does not transfer
+
+      virtual bool BuildDepends(vector<BuildDepRec> &BuildDeps) = 0;
+      static const char *BuildDepType(unsigned char Type);
+
       virtual bool Files(vector<pkgSrcRecords::File> &F) = 0;
       
-      Parser(FileFd *File,pkgSourceList::const_iterator SrcItem) : File(File), 
-             SrcItem(SrcItem) {};
-      virtual ~Parser() {delete File;};
+      Parser(const pkgIndexFile *Index) : iIndex(Index) {};
+      virtual ~Parser() {};
    };
    
    private:
@@ -78,5 +96,4 @@ class pkgSrcRecords
    ~pkgSrcRecords();
 };
 
-
 #endif

+ 259 - 23
apt-pkg/tagfile.cc

@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: tagfile.cc,v 1.25 1999/07/03 06:45:40 jgg Exp $
+// $Id: tagfile.cc,v 1.26 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
 
    Fast scanner for RFC-822 type header information
@@ -19,6 +19,8 @@
 #include <apt-pkg/error.h>
 #include <apt-pkg/strutl.h>
 
+#include <apti18n.h>
+    
 #include <string>
 #include <stdio.h>
 									/*}}}*/
@@ -26,16 +28,17 @@
 // TagFile::pkgTagFile - Constructor					/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-pkgTagFile::pkgTagFile(FileFd &Fd,unsigned long Size) : Fd(Fd), Size(Size)
+pkgTagFile::pkgTagFile(FileFd *pFd,unsigned long Size) : Fd(*pFd), Size(Size)
 {
    Buffer = new char[Size];
    Start = End = Buffer;
    Left = Fd.Size();
+   TotalSize = Fd.Size();
    iOffset = 0;
    Fill();
 }
 									/*}}}*/
-// pkgTagFile::~pkgTagFile - Destructor					/*{{{*/
+// TagFile::~pkgTagFile - Destructor					/*{{{*/
 // ---------------------------------------------------------------------
 /* */
 pkgTagFile::~pkgTagFile()
@@ -54,10 +57,12 @@ bool pkgTagFile::Step(pkgTagSection &Tag)
 	 return false;
       
       if (Tag.Scan(Start,End - Start) == false)
-	 return _error->Error("Unable to parse package file %s (1)",Fd.Name().c_str());
+	 return _error->Error(_("Unable to parse package file %s (1)"),Fd.Name().c_str());
    }   
    Start += Tag.size();
    iOffset += Tag.size();
+
+   Tag.Trim();
    
    return true;
 }
@@ -118,8 +123,18 @@ bool pkgTagFile::Fill()
    that is there */
 bool pkgTagFile::Jump(pkgTagSection &Tag,unsigned long Offset)
 {
+   // We are within a buffer space of the next hit..
+   if (Offset >= iOffset && iOffset + (End - Start) > Offset)
+   {
+      unsigned long Dist = Offset - iOffset;
+      Start += Dist;
+      iOffset += Dist;
+      return Step(Tag);
+   }
+
+   // Reposition and reload..
    iOffset = Offset;
-   Left = Fd.Size() - Offset;
+   Left = TotalSize - Offset;
    if (Fd.Seek(Offset) == false)
       return false;
    End = Start = Buffer;
@@ -135,10 +150,7 @@ bool pkgTagFile::Jump(pkgTagSection &Tag,unsigned long Offset)
       return false;
    
    if (Tag.Scan(Start,End - Start) == false)
-   {
-      cout << string(Start,End) << endl;
-      return _error->Error("Unable to parse package file %s (2)",Fd.Name().c_str());
-   }
+      return _error->Error(_("Unable to parse package file %s (2)"),Fd.Name().c_str());
    
    return true;
 }
@@ -148,6 +160,14 @@ bool pkgTagFile::Jump(pkgTagSection &Tag,unsigned long Offset)
 /* This looks for the first double new line in the data stream. It also
    indexes the tags in the section. This very simple hash function for the
    first 3 letters gives very good performance on the debian package files */
+inline static unsigned long AlphaHash(const char *Text, const char *End = 0)
+{
+   unsigned long Res = 0;
+   for (; Text != End && *Text != ':' && *Text != 0; Text++)
+      Res = (unsigned long)(*Text) ^ (Res << 2);
+   return Res & 0xFF;
+}
+
 bool pkgTagSection::Scan(const char *Start,unsigned long MaxLength)
 {
    const char *End = Start + MaxLength;
@@ -164,10 +184,7 @@ bool pkgTagSection::Scan(const char *Start,unsigned long MaxLength)
       if (isspace(Stop[0]) == 0)
       {
 	 Indexes[TagCount++] = Stop - Section;
-	 unsigned char A = tolower(Stop[0]) - 'a';
-	 unsigned char B = tolower(Stop[1]) - 'a';
-	 unsigned char C = tolower(Stop[3]) - 'a';
-	 AlphaIndexes[((A + C/3)%26) + 26*((B + C/2)%26)] = TagCount;
+	 AlphaIndexes[AlphaHash(Stop,End)] = TagCount;
       }
 
       Stop = (const char *)memchr(Stop,'\n',End - Stop);
@@ -191,17 +208,21 @@ bool pkgTagSection::Scan(const char *Start,unsigned long MaxLength)
    return false;
 }
 									/*}}}*/
+// TagSection::Trim - Trim off any trailing garbage			/*{{{*/
+// ---------------------------------------------------------------------
+/* There should be exactly 1 newline at the end of the buffer, no more. */
+void pkgTagSection::Trim()
+{
+   for (; Stop > Section + 2 && (Stop[-2] == '\n' || Stop[-2] == '\r'); Stop--);
+}
+									/*}}}*/
 // TagSection::Find - Locate a tag					/*{{{*/
 // ---------------------------------------------------------------------
 /* This searches the section for a tag that matches the given string. */
-bool pkgTagSection::Find(const char *Tag,const char *&Start,
-		         const char *&End)
+bool pkgTagSection::Find(const char *Tag,unsigned &Pos) const
 {
    unsigned int Length = strlen(Tag);
-   unsigned char A = tolower(Tag[0]) - 'a';
-   unsigned char B = tolower(Tag[1]) - 'a';
-   unsigned char C = tolower(Tag[3]) - 'a';
-   unsigned int I = AlphaIndexes[((A + C/3)%26) + 26*((B + C/2)%26)];
+   unsigned int I = AlphaIndexes[AlphaHash(Tag)];
    if (I == 0)
       return false;
    I--;
@@ -214,6 +235,39 @@ bool pkgTagSection::Find(const char *Tag,const char *&Start,
       if (strncasecmp(Tag,St,Length) != 0)
 	 continue;
 
+      // Make sure the colon is in the right place
+      const char *C = St + Length;
+      for (; isspace(*C) != 0; C++);
+      if (*C != ':')
+	 continue;
+      Pos = I;
+      return true;
+   }
+
+   Pos = 0;
+   return false;
+}
+									/*}}}*/
+// TagSection::Find - Locate a tag					/*{{{*/
+// ---------------------------------------------------------------------
+/* This searches the section for a tag that matches the given string. */
+bool pkgTagSection::Find(const char *Tag,const char *&Start,
+		         const char *&End) const
+{
+   unsigned int Length = strlen(Tag);
+   unsigned int I = AlphaIndexes[AlphaHash(Tag)];
+   if (I == 0)
+      return false;
+   I--;
+   
+   for (unsigned int Counter = 0; Counter != TagCount; Counter++, 
+	I = (I+1)%TagCount)
+   {
+      const char *St;
+      St = Section + Indexes[I];
+      if (strncasecmp(Tag,St,Length) != 0)
+	 continue;
+      
       // Make sure the colon is in the right place
       const char *C = St + Length;
       for (; isspace(*C) != 0; C++);
@@ -239,7 +293,7 @@ bool pkgTagSection::Find(const char *Tag,const char *&Start,
 // TagSection::FindS - Find a string					/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-string pkgTagSection::FindS(const char *Tag)
+string pkgTagSection::FindS(const char *Tag) const
 {
    const char *Start;
    const char *End;
@@ -251,7 +305,7 @@ string pkgTagSection::FindS(const char *Tag)
 // TagSection::FindI - Find an integer					/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-signed int pkgTagSection::FindI(const char *Tag,signed long Default)
+signed int pkgTagSection::FindI(const char *Tag,signed long Default) const
 {
    const char *Start;
    const char *Stop;
@@ -276,7 +330,7 @@ signed int pkgTagSection::FindI(const char *Tag,signed long Default)
 // ---------------------------------------------------------------------
 /* The bits marked in Flag are masked on/off in Flags */
 bool pkgTagSection::FindFlag(const char *Tag,unsigned long &Flags,
-			     unsigned long Flag)
+			     unsigned long Flag) const
 {
    const char *Start;
    const char *Stop;
@@ -294,9 +348,191 @@ bool pkgTagSection::FindFlag(const char *Tag,unsigned long &Flags,
       return true;
 
       default:
-      _error->Warning("Unknown flag value");
+      _error->Warning("Unknown flag value: %s",string(Start,Stop).c_str());
       return true;
    }
    return true;
 }
 									/*}}}*/
+
+// TFRewrite - Rewrite a control record					/*{{{*/
+// ---------------------------------------------------------------------
+/* This writes the control record to stdout rewriting it as necessary. The
+   override map item specificies the rewriting rules to follow. This also
+   takes the time to sort the feild list. */
+
+/* The order of this list is taken from dpkg source lib/parse.c the fieldinfos
+   array. */
+static const char *iTFRewritePackageOrder[] = {
+                          "Package",
+                          "Essential",
+                          "Status",
+                          "Priority",
+                          "Section",
+                          "Installed-Size",
+                          "Maintainer",
+                          "Architecture",
+                          "Source",
+                          "Version",
+                           "Revision",         // Obsolete
+                           "Config-Version",   // Obsolete
+                          "Replaces",
+                          "Provides",
+                          "Depends",
+                          "Pre-Depends",
+                          "Recommends",
+                          "Suggests",
+                          "Conflicts",
+                          "Conffiles",
+                          "Filename",
+                          "Size",
+                          "MD5Sum",
+                           "MSDOS-Filename",   // Obsolete
+                          "Description",
+                          0};
+static const char *iTFRewriteSourceOrder[] = {"Package",
+                                      "Source",
+                                      "Binary",
+                                      "Version",
+                                      "Priority",
+                                      "Section",
+                                      "Maintainer",
+                                      "Build-Depends",
+                                      "Build-Depends-Indep",
+                                      "Build-Conflicts",
+                                      "Build-Conflicts-Indep",
+                                      "Architecture",
+                                      "Standards-Version",
+                                      "Format",
+                                      "Directory",
+                                      "Files",
+                                      0};   
+
+/* Two levels of initialization are used because gcc will set the symbol
+   size of an array to the length of the array, causing dynamic relinking 
+   errors. Doing this makes the symbol size constant */
+const char **TFRewritePackageOrder = iTFRewritePackageOrder;
+const char **TFRewriteSourceOrder = iTFRewriteSourceOrder;
+   
+bool TFRewrite(FILE *Output,pkgTagSection const &Tags,const char *Order[],
+	       TFRewriteData *Rewrite)
+{
+   unsigned char Visited[256];   // Bit 1 is Order, Bit 2 is Rewrite
+   for (unsigned I = 0; I != 256; I++)
+      Visited[I] = 0;
+
+   // Set new tag up as necessary.
+   for (unsigned int J = 0; Rewrite != 0 && Rewrite[J].Tag != 0; J++)
+   {
+      if (Rewrite[J].NewTag == 0)
+	 Rewrite[J].NewTag = Rewrite[J].Tag;
+   }
+   
+   // Write all all of the tags, in order.
+   for (unsigned int I = 0; Order[I] != 0; I++)
+   {
+      bool Rewritten = false;
+      
+      // See if this is a field that needs to be rewritten
+      for (unsigned int J = 0; Rewrite != 0 && Rewrite[J].Tag != 0; J++)
+      {
+	 if (strcasecmp(Rewrite[J].Tag,Order[I]) == 0)
+	 {
+	    Visited[J] |= 2;
+	    if (Rewrite[J].Rewrite != 0 && Rewrite[J].Rewrite[0] != 0)
+	    {
+	       if (isspace(Rewrite[J].Rewrite[0]))
+		  fprintf(Output,"%s:%s\n",Rewrite[J].NewTag,Rewrite[J].Rewrite);
+	       else
+		  fprintf(Output,"%s: %s\n",Rewrite[J].NewTag,Rewrite[J].Rewrite);
+	    }
+	    
+	    Rewritten = true;
+	    break;
+	 }
+      }      
+	    
+      // See if it is in the fragment
+      unsigned Pos;
+      if (Tags.Find(Order[I],Pos) == false)
+	 continue;
+      Visited[Pos] |= 1;
+
+      if (Rewritten == true)
+	 continue;
+      
+      /* Write out this element, taking a moment to rewrite the tag
+         in case of changes of case. */
+      const char *Start;
+      const char *Stop;
+      Tags.Get(Start,Stop,Pos);
+      
+      if (fputs(Order[I],Output) < 0)
+	 return _error->Errno("fputs","IO Error to output");
+      Start += strlen(Order[I]);
+      if (fwrite(Start,Stop - Start,1,Output) != 1)
+	 return _error->Errno("fwrite","IO Error to output");
+      if (Stop[-1] != '\n')
+	 fprintf(Output,"\n");
+   }   
+
+   // Now write all the old tags that were missed.
+   for (unsigned int I = 0; I != Tags.Count(); I++)
+   {
+      if ((Visited[I] & 1) == 1)
+	 continue;
+
+      const char *Start;
+      const char *Stop;
+      Tags.Get(Start,Stop,I);
+      const char *End = Start;
+      for (; End < Stop && *End != ':'; End++);
+
+      // See if this is a field that needs to be rewritten
+      bool Rewritten = false;
+      for (unsigned int J = 0; Rewrite != 0 && Rewrite[J].Tag != 0; J++)
+      {
+	 if (stringcasecmp(Start,End,Rewrite[J].Tag) == 0)
+	 {
+	    Visited[J] |= 2;
+	    if (Rewrite[J].Rewrite != 0 && Rewrite[J].Rewrite[0] != 0)
+	    {
+	       if (isspace(Rewrite[J].Rewrite[0]))
+		  fprintf(Output,"%s:%s\n",Rewrite[J].NewTag,Rewrite[J].Rewrite);
+	       else
+		  fprintf(Output,"%s: %s\n",Rewrite[J].NewTag,Rewrite[J].Rewrite);
+	    }
+	    
+	    Rewritten = true;
+	    break;
+	 }
+      }      
+      
+      if (Rewritten == true)
+	 continue;
+      
+      // Write out this element
+      if (fwrite(Start,Stop - Start,1,Output) != 1)
+	 return _error->Errno("fwrite","IO Error to output");
+      if (Stop[-1] != '\n')
+	 fprintf(Output,"\n");
+   }
+   
+   // Now write all the rewrites that were missed
+   for (unsigned int J = 0; Rewrite != 0 && Rewrite[J].Tag != 0; J++)
+   {
+      if ((Visited[J] & 2) == 2)
+	 continue;
+      
+      if (Rewrite[J].Rewrite != 0 && Rewrite[J].Rewrite[0] != 0)
+      {
+	 if (isspace(Rewrite[J].Rewrite[0]))
+	    fprintf(Output,"%s:%s\n",Rewrite[J].NewTag,Rewrite[J].Rewrite);
+	 else
+	    fprintf(Output,"%s: %s\n",Rewrite[J].NewTag,Rewrite[J].Rewrite);
+      }      
+   }
+      
+   return true;
+}
+									/*}}}*/

+ 34 - 15
apt-pkg/tagfile.h

@@ -1,12 +1,12 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: tagfile.h,v 1.14 1999/07/03 06:45:40 jgg Exp $
+// $Id: tagfile.h,v 1.15 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
 
    Fast scanner for RFC-822 type header information
    
    This parser handles Debian package files (and others). Their form is
-   RFC-822 type header fields in groups seperated by a blank line.
+   RFC-822 type header fields in groups separated by a blank line.
    
    The parser reads the file and provides methods to step linearly
    over it or to jump to a pre-recorded start point and read that record.
@@ -17,7 +17,6 @@
    
    ##################################################################### */
 									/*}}}*/
-// Header section: pkglib
 #ifndef PKGLIB_TAGFILE_H
 #define PKGLIB_TAGFILE_H
 
@@ -26,7 +25,8 @@
 #endif 
 
 #include <apt-pkg/fileutl.h>
-
+#include <stdio.h>
+    
 class pkgTagSection
 {
    const char *Section;
@@ -34,7 +34,7 @@ class pkgTagSection
    
    // We have a limit of 256 tags per section.
    unsigned short Indexes[256];
-   unsigned short AlphaIndexes[26 + 26*26];
+   unsigned short AlphaIndexes[0xff];
    
    unsigned int TagCount;
      
@@ -43,19 +43,21 @@ class pkgTagSection
    inline bool operator ==(const pkgTagSection &rhs) {return Section == rhs.Section;};
    inline bool operator !=(const pkgTagSection &rhs) {return Section != rhs.Section;};
    
-   bool Find(const char *Tag,const char *&Start, const char *&End);
-   string FindS(const char *Tag);
-   signed int FindI(const char *Tag,signed long Default = 0);
+   bool Find(const char *Tag,const char *&Start, const char *&End) const;
+   bool Find(const char *Tag,unsigned &Pos) const;
+   string FindS(const char *Tag) const;
+   signed int FindI(const char *Tag,signed long Default = 0) const ;
    bool pkgTagSection::FindFlag(const char *Tag,unsigned long &Flags,
-				unsigned long Flag);
+				unsigned long Flag) const;
    bool Scan(const char *Start,unsigned long MaxLength);
-   inline unsigned long size() {return Stop - Section;};
-
-   inline unsigned int Count() {return TagCount;};
-   inline void Get(const char *&Start,const char *&Stop,unsigned int I)
+   inline unsigned long size() const {return Stop - Section;};
+   void Trim();
+   
+   inline unsigned int Count() const {return TagCount;};
+   inline void Get(const char *&Start,const char *&Stop,unsigned int I) const
                    {Start = Section + Indexes[I]; Stop = Section + Indexes[I+1];}
 	    
-   inline void GetSection(const char *&Start,const char *&Stop)
+   inline void GetSection(const char *&Start,const char *&Stop) const
    {
       Start = Section;
       Stop = this->Stop;
@@ -73,6 +75,7 @@ class pkgTagFile
    unsigned long Left;
    unsigned long iOffset;
    unsigned long Size;
+   unsigned long TotalSize;
    
    bool Fill();
    
@@ -82,8 +85,24 @@ class pkgTagFile
    inline unsigned long Offset() {return iOffset;};
    bool Jump(pkgTagSection &Tag,unsigned long Offset);
 
-   pkgTagFile(FileFd &F,unsigned long Size = 32*1024);
+   pkgTagFile(FileFd *F,unsigned long Size = 32*1024);
    ~pkgTagFile();
 };
 
+/* This is the list of things to rewrite. The rewriter
+   goes through and changes or adds each of these headers
+   to suit. A zero forces the header to be erased, an empty string
+   causes the old value to be used. (rewrite rule ignored) */
+struct TFRewriteData
+{
+   const char *Tag;
+   const char *Rewrite;
+   const char *NewTag;
+};
+extern const char **TFRewritePackageOrder;
+extern const char **TFRewriteSourceOrder;
+
+bool TFRewrite(FILE *Output,pkgTagSection const &Tags,const char *Order[],
+	       TFRewriteData *Rewrite);
+
 #endif

+ 17 - 244
apt-pkg/version.cc

@@ -1,18 +1,9 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: version.cc,v 1.9 1999/04/19 06:03:09 jgg Exp $
+// $Id: version.cc,v 1.10 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
 
-   Version - Version string 
-   
-   Version comparing is done using the == and < operators. STL's
-   function.h provides the remaining set of comparitors. A directly
-   callable non-string class version is provided for functions manipulating
-   the cache file (esp the sort function).
- 
-   A version is defined to be equal if a case sensitive compare returns
-   that the two strings are the same. For compatibility with the QSort
-   function this version returns -1,0,1.
+   Version - Versioning system..
    
    ##################################################################### */
 									/*}}}*/
@@ -26,246 +17,28 @@
 
 #include <stdlib.h>
 									/*}}}*/
+    
+static pkgVersioningSystem *VSList[10];
+pkgVersioningSystem **pkgVersioningSystem::GlobalList = VSList;
+unsigned long pkgVersioningSystem::GlobalListLen = 0;
 
-// StrToLong - Convert the string between two iterators to a long	/*{{{*/
+// pkgVS::pkgVersioningSystem - Constructor				/*{{{*/
 // ---------------------------------------------------------------------
-/* */
-static unsigned long StrToLong(const char *begin,const char *end)
+/* Link to the global list of versioning systems supported */
+pkgVersioningSystem::pkgVersioningSystem()
 {
-   char S[40];
-   char *I = S;
-   for (; begin != end && I < S + 40;)
-      *I++ = *begin++;
-   *I = 0;
-   return strtoul(S,0,10);
+   VSList[GlobalListLen] = this;
+   GlobalListLen++;
 }
 									/*}}}*/
-// VersionCompare (op) - Greater than comparison for versions		/*{{{*/
+// pkgVS::GetVS - Find a VS by name					/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-int pkgVersionCompare(const char *A, const char *B)
-{
-   return pkgVersionCompare(A,A + strlen(A),B,B + strlen(B));
-}
-int pkgVersionCompare(string A,string B)
-{
-   return pkgVersionCompare(A.begin(),A.end(),B.begin(),B.end());
-}
-
-									/*}}}*/
-// iVersionCompare - Compare versions					/*{{{*/
-// ---------------------------------------------------------------------
-/* This compares a fragment of the version. */
-static int iVersionCompare(const char *A, const char *AEnd, const char *B,
-			   const char *BEnd)
-{
-   if (A >= AEnd && B >= BEnd)
-      return 0;
-   if (A >= AEnd)
-      return -1;
-   if (B >= BEnd)
-      return 1;
-   
-   /* Iterate over the whole string
-      What this does is to spilt the whole string into groups of 
-      numeric and non numeric portions. For instance:
-         a67bhgs89
-      Has 4 portions 'a', '67', 'bhgs', '89'. A more normal:
-         2.7.2-linux-1
-      Has '2', '.', '7', '.' ,'-linux-','1' */
-   const char *lhs = A;
-   const char *rhs = B;
-   while (lhs != AEnd && rhs != BEnd)
-   {
-      // Starting points
-      const char *Slhs = lhs;
-      const char *Srhs = rhs;
-      
-      // Compute ending points were we have passed over the portion
-      bool Digit = (isdigit(*lhs) > 0?true:false);
-      for (;lhs != AEnd && (isdigit(*lhs) > 0?true:false) == Digit; lhs++);
-      for (;rhs != BEnd && (isdigit(*rhs) > 0?true:false) == Digit; rhs++);
-      
-      if (Digit == true)
-      {
-	 // If the lhs has a digit and the rhs does not then <
-	 if (rhs - Srhs == 0)
-	    return -1;
-	 
-	 // Generate integers from the strings.
-	 unsigned long Ilhs = StrToLong(Slhs,lhs);
-	 unsigned long Irhs = StrToLong(Srhs,rhs);
-	 if (Ilhs != Irhs)
-	 {
-	    if (Ilhs > Irhs)
-	       return 1;
-	    return -1;
-	 }
-      }
-      else
-      {
-	 // They are equal length so do a straight text compare
-	 for (;Slhs != lhs && Srhs != rhs; Slhs++, Srhs++)
-	 {
-	    if (*Slhs != *Srhs)
-	    {
-	       /* We need to compare non alpha chars as higher than alpha
-	          chars (a < !) */
-	       int lc = *Slhs;
-	       int rc = *Srhs;
-	       if (isalpha(lc) == 0) lc += 256;
-	       if (isalpha(rc) == 0) rc += 256;
-	       if (lc > rc)
-		  return 1;
-	       return -1;
-	    }
-	 }
-
-	 // If the lhs is shorter than the right it is 'less'
-	 if (lhs - Slhs < rhs - Srhs)
-	    return -1;
-
-	 // If the lhs is longer than the right it is 'more'
-	 if (lhs - Slhs > rhs - Srhs)
-	    return 1;		 
-      }      
-   }
-
-   // The strings must be equal
-   if (lhs == AEnd && rhs == BEnd)
-      return 0;
-
-   // lhs is shorter
-   if (lhs == AEnd)
-      return -1;
-
-   // rhs is shorter
-   if (rhs == BEnd)
-      return 1;
-       
-   // Shouldnt happen
-   return 1;
-}
-									/*}}}*/
-// VersionCompare - Comparison for versions				/*{{{*/
-// ---------------------------------------------------------------------
-/* This fragments the version into E:V-R triples and compares each 
-   portion seperately. */
-int pkgVersionCompare(const char *A, const char *AEnd, const char *B,
-		      const char *BEnd)
+pkgVersioningSystem *pkgVersioningSystem::GetVS(const char *Label)
 {
-   // Strip off the epoch and compare it 
-   const char *lhs = A;
-   const char *rhs = B;
-   for (;lhs != AEnd && *lhs != ':'; lhs++);
-   for (;rhs != BEnd && *rhs != ':'; rhs++);
-   if (lhs == AEnd)
-      lhs = A;
-   if (rhs == BEnd)
-      rhs = B;
-   
-   // Compare the epoch
-   int Res = iVersionCompare(A,lhs,B,rhs);
-   if (Res != 0)
-      return Res;
-
-   // Skip the :
-   if (lhs != A)
-      lhs++;
-   if (rhs != B)
-      rhs++;
-   
-   // Find the last - 
-   const char *dlhs = AEnd-1;
-   const char *drhs = BEnd-1;
-   for (;dlhs > lhs && *dlhs != '-'; dlhs--);
-   for (;drhs > rhs && *drhs != '-'; drhs--);
-
-   if (dlhs == lhs)
-      dlhs = AEnd;
-   if (drhs == rhs)
-      drhs = BEnd;
-   
-   // Compare the main version
-   Res = iVersionCompare(lhs,dlhs,rhs,drhs);
-   if (Res != 0)
-      return Res;
-   
-   // Skip the -
-   if (dlhs != lhs)
-      dlhs++;
-   if (drhs != rhs)
-      drhs++;
-   return iVersionCompare(dlhs,AEnd,drhs,BEnd);
-}
-									/*}}}*/
-// CheckDep - Check a single dependency					/*{{{*/
-// ---------------------------------------------------------------------
-/* This simply preforms the version comparison and switch based on 
-   operator. */
-bool pkgCheckDep(const char *DepVer,const char *PkgVer,int Op)
-{
-   if (DepVer == 0)
-      return true;
-   if (PkgVer == 0)
-      return false;
-   
-   // Perform the actuall comparision.
-   int Res = pkgVersionCompare(PkgVer,DepVer);
-   switch (Op & 0x0F)
-   {
-      case pkgCache::Dep::LessEq:
-      if (Res <= 0)
-	 return true;
-      break;
-      
-      case pkgCache::Dep::GreaterEq:
-      if (Res >= 0)
-	 return true;
-      break;
-      
-      case pkgCache::Dep::Less:
-      if (Res < 0)
-	 return true;
-      break;
-      
-      case pkgCache::Dep::Greater:
-      if (Res > 0)
-	 return true;
-      break;
-      
-      case pkgCache::Dep::Equals:
-      if (Res == 0)
-	 return true;
-      break;
-      
-      case pkgCache::Dep::NotEquals:
-      if (Res != 0)
-	 return true;
-      break;
-   }
-
-   return false;
-}
-									/*}}}*/
-// BaseVersion - Return the upstream version string			/*{{{*/
-// ---------------------------------------------------------------------
-/* This strips all the debian specific information from the version number */
-string pkgBaseVersion(const char *Ver)
-{
-   // Strip off the bit before the first colon
-   const char *I = Ver;
-   for (; *I != 0 && *I != ':'; I++);
-   if (*I == ':')
-      Ver = I + 1;
-   
-   // Chop off the trailing -
-   I = Ver;
-   unsigned Last = strlen(Ver);
-   for (; *I != 0; I++)
-      if (*I == '-')
-	 Last = I - Ver;
-   
-   return string(Ver,Last);
+   for (unsigned I = 0; I != GlobalListLen; I++)
+      if (strcmp(VSList[I]->Label,Label) == 0)
+	 return VSList[I];
+   return 0;
 }
 									/*}}}*/

+ 58 - 11
apt-pkg/version.h

@@ -1,16 +1,22 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: version.h,v 1.5 1999/04/19 06:03:09 jgg Exp $
+// $Id: version.h,v 1.6 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
 
-   Version - Version comparison routines
+   Version - Versioning system..
+
+   The versioning system represents how versions are compared, represented
+   and how dependencies are evaluated. As a general rule versioning
+   systems are not compatible unless specifically allowed by the 
+   TestCompatibility query.
    
-   These routines provide some means to compare versions and check
-   dependencies.
+   The versions are stored in a global list of versions, but that is just
+   so that they can be queried when someone does 'apt-get -v'. 
+   pkgSystem provides the proper means to access the VS for the active
+   system.
    
    ##################################################################### */
 									/*}}}*/
-// Header section: pkglib
 #ifndef PKGLIB_VERSION_H
 #define PKGLIB_VERSION_H
 
@@ -20,11 +26,52 @@
 
 #include <string>
 
-int pkgVersionCompare(const char *A, const char *B);
-int pkgVersionCompare(const char *A, const char *AEnd, const char *B, 
-		   const char *BEnd);
-int pkgVersionCompare(string A,string B);
-bool pkgCheckDep(const char *DepVer,const char *PkgVer,int Op);
-string pkgBaseVersion(const char *Ver);
+class pkgVersioningSystem
+{
+   public:
+   // Global list of VS's
+   static pkgVersioningSystem **GlobalList;
+   static unsigned long GlobalListLen;
+   static pkgVersioningSystem *GetVS(const char *Label);
+   
+   const char *Label;
+   
+   // Compare versions..
+   virtual int DoCmpVersion(const char *A,const char *Aend,
+			  const char *B,const char *Bend) = 0;   
+   virtual bool CheckDep(const char *PkgVer,int Op,const char *DepVer) = 0;
+   virtual int DoCmpReleaseVer(const char *A,const char *Aend,
+			       const char *B,const char *Bend) = 0;
+   virtual string UpstreamVersion(const char *A) = 0;
+   
+   // See if the given VS is compatible with this one.. 
+   virtual bool TestCompatibility(pkgVersioningSystem const &Against) 
+                {return this == &Against;};
+
+   // Shortcuts
+   inline int CmpVersion(const char *A, const char *B)
+   {
+      return DoCmpVersion(A,A+strlen(A),B,B+strlen(B));
+   };
+   inline int CmpVersion(string A,string B)
+   {
+      return DoCmpVersion(A.begin(),A.end(),B.begin(),B.end());
+   };  
+   inline int CmpReleaseVer(const char *A, const char *B)
+   {
+      return DoCmpReleaseVer(A,A+strlen(A),B,B+strlen(B));
+   };
+   inline int CmpReleaseVer(string A,string B)
+   {
+      return DoCmpReleaseVer(A.begin(),A.end(),B.begin(),B.end());
+   };  
+   
+   pkgVersioningSystem();
+   virtual ~pkgVersioningSystem() {};
+};
+
+#ifdef APT_COMPATIBILITY
+#include <apt-pkg/debversion.h>
+#endif
 
 #endif

+ 210 - 0
apt-pkg/versionmatch.cc

@@ -0,0 +1,210 @@
+// -*- mode: cpp; mode: fold -*-
+// Description								/*{{{*/
+// $Id: versionmatch.cc,v 1.2 2001/02/20 07:03:17 jgg Exp $
+/* ######################################################################
+
+   Version Matching 
+   
+   This module takes a matching string and a type and locates the version
+   record that satisfies the constraint described by the matching string.
+   
+   ##################################################################### */
+									/*}}}*/
+// Include Files							/*{{{*/
+#ifdef __GNUG__
+#pragma implementation "apt-pkg/versionmatch.h"
+#endif
+#include <apt-pkg/versionmatch.h>
+
+#include <apt-pkg/strutl.h>
+#include <apt-pkg/error.h>
+
+#include <stdio.h>
+									/*}}}*/
+
+// VersionMatch::pkgVersionMatch - Constructor				/*{{{*/
+// ---------------------------------------------------------------------
+/* Break up the data string according to the selected type */
+pkgVersionMatch::pkgVersionMatch(string Data,MatchType Type) : Type(Type)
+{
+   if (Type == None || Data.length() < 1)
+      return;
+   
+   // Cut up the version representation
+   if (Type == Version)
+   {
+      if (Data.end()[-1] == '*')
+      {
+	 VerPrefixMatch = true;
+	 VerStr = string(Data.begin(),Data.end()-1);
+      }
+      else
+	 VerStr = Data;
+      return;
+   }   
+   
+   if (Type == Release)
+   {
+      // All empty = match all
+      if (Data == "*")
+	 return;
+      
+      // Are we a simple specification?
+      const char *I = Data.begin();
+      for (; I < Data.end() && *I != '='; I++);	 
+      if (I == Data.end())
+      {
+	 // Temporary
+	 if (isdigit(Data[0]))
+	    RelVerStr = Data;
+	 else
+	    RelArchive = Data;
+	 
+	 if (RelVerStr.end()[-1] == '*')
+	 {
+	    RelVerPrefixMatch = true;
+	    RelVerStr = string(RelVerStr.begin(),RelVerStr.end()-1);
+	 }	 
+	 return;
+      }
+            
+      char Spec[300];
+      char *Fragments[20];
+      snprintf(Spec,sizeof(Spec),"%s",Data.c_str());
+      if (TokSplitString(',',Spec,Fragments,
+			 sizeof(Fragments)/sizeof(Fragments[0])) == false)
+      {
+	 Type = None;
+	 return;
+      }
+      
+      for (unsigned J = 0; Fragments[J] != 0; J++)
+      {
+	 if (strlen(Fragments[J]) < 3)
+	    continue;
+	    
+	 if (stringcasecmp(Fragments[J],Fragments[J]+2,"v=") == 0)
+	    RelVerStr = Fragments[J]+2;
+	 else if (stringcasecmp(Fragments[J],Fragments[J]+2,"o=") == 0)
+	    RelOrigin = Fragments[J]+2;
+	 else if (stringcasecmp(Fragments[J],Fragments[J]+2,"a=") == 0)
+	    RelArchive = Fragments[J]+2;
+	 else if (stringcasecmp(Fragments[J],Fragments[J]+2,"l=") == 0)
+	    RelLabel = Fragments[J]+2;
+	 else if (stringcasecmp(Fragments[J],Fragments[J]+2,"c=") == 0)
+	    RelComponent = Fragments[J]+2;
+      }
+      
+      if (RelVerStr.end()[-1] == '*')
+      {
+	 RelVerPrefixMatch = true;
+	 RelVerStr = string(RelVerStr.begin(),RelVerStr.end()-1);
+      }	 
+      return;
+   }
+   
+   if (Type == Origin)
+   {
+      OrSite = Data;
+      return;
+   }   
+}
+									/*}}}*/
+// VersionMatch::MatchVer - Match a version string with prefixing	/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool pkgVersionMatch::MatchVer(const char *A,string B,bool Prefix)
+{   
+   const char *Ab = A;
+   const char *Ae = Ab + strlen(A);
+   
+   // Strings are not a compatible size.
+   if ((unsigned)(Ae - Ab) != B.length() && Prefix == false ||
+       (unsigned)(Ae - Ab) < B.length())
+      return false;
+   
+   // Match (leading?)
+   if (stringcasecmp(B.begin(),B.end(),
+		     Ab,Ab + B.length()) == 0)
+      return true;
+   
+   return false;
+}
+									/*}}}*/
+// VersionMatch::Find - Locate the best match for the select type	/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+pkgCache::VerIterator pkgVersionMatch::Find(pkgCache::PkgIterator Pkg)
+{
+   pkgCache::VerIterator Ver = Pkg.VersionList();
+   for (; Ver.end() == false; Ver++)
+   {
+      if (Type == Version)
+      {
+	 if (MatchVer(Ver.VerStr(),VerStr,VerPrefixMatch) == true)
+	    return Ver;
+	 continue;
+      }
+      
+      for (pkgCache::VerFileIterator VF = Ver.FileList(); VF.end() == false; VF++)
+	 if (FileMatch(VF.File()) == true)
+	    return Ver;
+   }
+      
+   // This will be Ended by now.
+   return Ver;
+}
+									/*}}}*/
+// VersionMatch::FileMatch - Match against an index file		/*{{{*/
+// ---------------------------------------------------------------------
+/* This matcher checks against the release file and the origin location 
+   to see if the constraints are met. */
+bool pkgVersionMatch::FileMatch(pkgCache::PkgFileIterator File)
+{
+   if (Type == Release)
+   {
+/*      cout << RelVerStr << ',' << RelOrigin << ',' << RelArchive << ',' << RelLabel << endl;
+      cout << File.Version() << ',' << File.Origin() << ',' << File.Archive() << ',' << File.Label() << endl;
+*/
+      if (RelVerStr.empty() == true && RelOrigin.empty() == true &&
+	  RelArchive.empty() == true && RelLabel.empty() == true &&
+	  RelComponent.empty() == true)
+	 return false;
+      
+      if (RelVerStr.empty() == false)
+	 if (File->Version == 0 ||
+	     MatchVer(File.Version(),RelVerStr,RelVerPrefixMatch) == false)
+	    return false;
+      if (RelOrigin.empty() == false)
+	 if (File->Origin == 0 ||
+	     stringcasecmp(RelOrigin,File.Origin()) != 0)
+	    return false;
+      if (RelArchive.empty() == false)
+      {
+	 if (File->Archive == 0 || 
+	     stringcasecmp(RelArchive,File.Archive()) != 0)
+	    return false;
+      }      
+      if (RelLabel.empty() == false)
+	 if (File->Label == 0 ||
+	     stringcasecmp(RelLabel,File.Label()) != 0)
+	    return false;
+      if (RelComponent.empty() == false)
+	 if (File->Component == 0 ||
+	     stringcasecmp(RelLabel,File.Component()) != 0)
+	    return false;
+      return true;
+   }
+   
+   if (Type == Origin)
+   {
+      if (OrSite.empty() == false)
+	 if (File->Site == 0 ||
+	     OrSite != File.Site())
+	    return false;
+      return true;
+   }
+   
+   return false;
+}
+									/*}}}*/

+ 69 - 0
apt-pkg/versionmatch.h

@@ -0,0 +1,69 @@
+// -*- mode: cpp; mode: fold -*-
+// Description								/*{{{*/
+// $Id: versionmatch.h,v 1.2 2001/02/20 07:03:17 jgg Exp $
+/* ######################################################################
+
+   Version Matching 
+   
+   This module takes a matching string and a type and locates the version
+   record that satisfies the constraint described by the matching string.
+
+     Version: 1.2*
+     Release: o=Debian,v=2.1*,c=main
+     Release: v=2.1*
+     Release: *
+     Origin: ftp.debian.org
+   
+   Release may be a complex type that can specify matches for any of:
+      Version (v= with prefix)
+      Origin (o=)
+      Archive (a=)
+      Label (l=)
+      Component (c=)
+   If there are no equals signs in the string then it is scanned in short
+   form - if it starts with a number it is Version otherwise it is an 
+   Archive.
+   
+   Release may be a '*' to match all releases.
+   
+   ##################################################################### */
+									/*}}}*/
+#ifndef PKGLIB_VERSIONMATCH_H
+#define PKGLIB_VERSIONMATCH_H
+
+#ifdef __GNUG__
+#pragma interface "apt-pkg/versionmatch.h"
+#endif
+
+#include <string>
+#include <apt-pkg/pkgcache.h>
+
+class pkgVersionMatch
+{
+   // Version Matching
+   string VerStr;
+   bool VerPrefixMatch;
+
+   // Release Matching
+   string RelVerStr;
+   bool RelVerPrefixMatch;
+   string RelOrigin;
+   string RelArchive;
+   string RelLabel;
+   string RelComponent;
+
+   // Origin Matching
+   string OrSite;
+   
+   public:
+   
+   enum MatchType {None = 0,Version,Release,Origin} Type;
+   
+   bool MatchVer(const char *A,string B,bool Prefix);
+   bool FileMatch(pkgCache::PkgFileIterator File);
+   pkgCache::VerIterator Find(pkgCache::PkgIterator Pkg);
+			       
+   pkgVersionMatch(string Data,MatchType Type);
+};
+
+#endif

+ 1 - 0
buildlib/apti18n.h.in

@@ -0,0 +1 @@
+#define _(x) x

+ 22 - 32
buildlib/archtable

@@ -1,34 +1,24 @@
 # This file contains a table of known architecture strings, with
-# things to map them to. `configure' will take the output of gcc
-# --print-libgcc-file-name, strip off leading directories up to and
-# including gcc-lib, strip off trailing /libgcc.a and trailing version
-# number directory, and then strip off everything after the first
-# hyphen.  The idea is that you're left with this bit:
-#   $ gcc --print-libgcc-file-name
-#   /usr/lib/gcc-lib/i486-linux/2.7.2/libgcc.a
-#                    ^^^^
-# This is then looked up in the table below, to find out what to map
-# it to.  If it isn't found then configure will print a warning and
-# continue.  You can override configure's ideas using --with-arch.
-# The third field is the GNU configure architecture to use with
-# this build architecture.
-#
-# This file is mirrored from dpkg.
-#
+# things to map them to. `configure' will take the output of the
+# autoconf cannon macros and look in here. This only deals with architecture
+# (CPU) names.
 
-i386	i386	i486
-i486	i386	i486
-i586	i386	i486
-i686	i386	i486
-pentium	i386	i486
-sparc	sparc	sparc
-sparc64	sparc64	sparc64
-alpha	alpha	alpha
-m68k	m68k	m68k
-arm	arm	arm
-armv4l  arm     arm
-powerpc	powerpc	powerpc
-ppc	powerpc	powerpc
-mipsel  mipsel  mipsel
-mips	mips	mips
-hppa1.1 hppa    hppa
+# The left side is a regex for awk
+
+i.86	i386
+pentium	i386
+sparc	sparc
+sparc64	sparc
+alpha.*	alpha
+m68k	m68k
+arm.*	arm
+powerpc	powerpc
+ppc	powerpc
+mipsel  mipsel
+mipseb	mips
+mips	mips
+sheb	sheb
+shel	sh
+sh	sh
+hppa.*	hppa
+ia64	ia64

+ 327 - 112
buildlib/config.guess

@@ -1,8 +1,10 @@
 #! /bin/sh
 # Attempt to guess a canonical system name.
-#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000
 #   Free Software Foundation, Inc.
-#
+
+version='2000-09-27'
+
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 2 of the License, or
@@ -23,8 +25,7 @@
 # the same distribution terms that you use for the rest of that program.
 
 # Written by Per Bothner <bothner@cygnus.com>.
-# The master version of this file is at the FSF in /home/gd/gnu/lib.
-# Please send patches to the Autoconf mailing list <autoconf@gnu.org>.
+# Please send patches to <config-patches@gnu.org>.
 #
 # This script attempts to guess a canonical system name similar to
 # config.sub.  If it succeeds, it prints the system name on stdout, and
@@ -37,6 +38,46 @@
 # (but try to keep the structure clean).
 #
 
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of this system.
+
+Operation modes:
+  -h, --help               print this help, then exit
+  -V, --version            print version number, then exit"
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case "$1" in
+    --version | --vers* | -V )
+       echo "$version" ; exit 0 ;;
+    --help | --h* | -h )
+       echo "$usage"; exit 0 ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       exec >&2
+       echo "$me: invalid option $1"
+       echo "$help"
+       exit 1 ;;
+    * )
+       break ;;
+  esac
+done
+
+if test $# != 0; then
+  echo "$me: too many arguments$help" >&2
+  exit 1
+fi
+
 # Use $HOST_CC if defined. $CC may point to a cross-compiler
 if test x"$CC_FOR_BUILD" = x; then
   if test x"$HOST_CC" != x; then
@@ -68,6 +109,43 @@ trap 'rm -f $dummy.c $dummy.o $dummy; exit 1' 1 2 15
 # Note: order is significant - the case branches are not exclusive.
 
 case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    *:NetBSD:*:*)
+	# Netbsd (nbsd) targets should (where applicable) match one or
+	# more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+	# *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
+	# switched to ELF, *-*-netbsd* would select the old
+	# object file format.  This provides both forward
+	# compatibility and a consistent mechanism for selecting the
+	# object file format.
+	# Determine the machine/vendor (is the vendor relevant).
+	case "${UNAME_MACHINE}" in
+	    amiga) machine=m68k-unknown ;;
+	    arm32) machine=arm-unknown ;;
+	    atari*) machine=m68k-atari ;;
+	    sun3*) machine=m68k-sun ;;
+	    mac68k) machine=m68k-apple ;;
+	    macppc) machine=powerpc-apple ;;
+	    hp3[0-9][05]) machine=m68k-hp ;;
+	    ibmrt|romp-ibm) machine=romp-ibm ;;
+	    *) machine=${UNAME_MACHINE}-unknown ;;
+	esac
+	# The Operating System including object format.
+	if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+		| grep __ELF__ >/dev/null
+	then
+	    # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+	    # Return netbsd for either.  FIX?
+	    os=netbsd
+	else
+	    os=netbsdelf
+	fi
+	# The OS release
+	release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+	# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+	# contains redundant information, the shorter form:
+	# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+	echo "${machine}-${os}${release}"
+	exit 0 ;;
     alpha:OSF1:*:*)
 	if test $UNAME_RELEASE = "V4.0"; then
 		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
@@ -77,41 +155,51 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
 	# A Xn.n version is an unreleased experimental baselevel.
 	# 1.2 uses "1.2" for uname -r.
 	cat <<EOF >$dummy.s
+	.data
+\$Lformat:
+	.byte 37,100,45,37,120,10,0	# "%d-%x\n"
+
+	.text
 	.globl main
+	.align 4
 	.ent main
 main:
-	.frame \$30,0,\$26,0
-	.prologue 0
-	.long 0x47e03d80 # implver $0
-	lda \$2,259
-	.long 0x47e20c21 # amask $2,$1
-	srl \$1,8,\$2
-	sll \$2,2,\$2
-	sll \$0,3,\$0
-	addl \$1,\$0,\$0
-	addl \$2,\$0,\$0
-	ret \$31,(\$26),1
+	.frame \$30,16,\$26,0
+	ldgp \$29,0(\$27)
+	.prologue 1
+	.long 0x47e03d80 # implver \$0
+	lda \$2,-1
+	.long 0x47e20c21 # amask \$2,\$1
+	lda \$16,\$Lformat
+	mov \$0,\$17
+	not \$1,\$18
+	jsr \$26,printf
+	ldgp \$29,0(\$26)
+	mov 0,\$16
+	jsr \$26,exit
 	.end main
 EOF
 	$CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null
 	if test "$?" = 0 ; then
-		./$dummy
-		case "$?" in
-			7)
+		case `./$dummy` in
+			0-0)
 				UNAME_MACHINE="alpha"
 				;;
-			15)
+			1-0)
 				UNAME_MACHINE="alphaev5"
 				;;
-			14)
+			1-1)
 				UNAME_MACHINE="alphaev56"
 				;;
-			10)
+			1-101)
 				UNAME_MACHINE="alphapca56"
 				;;
-			16)
+			2-303)
 				UNAME_MACHINE="alphaev6"
 				;;
+			2-307)
+				UNAME_MACHINE="alphaev67"
+				;;
 		esac
 	fi
 	rm -f $dummy.s $dummy
@@ -127,11 +215,8 @@ EOF
 	echo alpha-dec-winnt3.5
 	exit 0 ;;
     Amiga*:UNIX_System_V:4.0:*)
-	echo m68k-cbm-sysv4
+	echo m68k-unknown-sysv4
 	exit 0;;
-    amiga:NetBSD:*:*)
-      echo m68k-cbm-netbsd${UNAME_RELEASE}
-      exit 0 ;;
     amiga:OpenBSD:*:*)
 	echo m68k-unknown-openbsd${UNAME_RELEASE}
 	exit 0 ;;
@@ -156,12 +241,12 @@ EOF
     wgrisc:OpenBSD:*:*)
 	echo mipsel-unknown-openbsd${UNAME_RELEASE}
 	exit 0 ;;
+    *:OS/390:*:*)
+	echo i370-ibm-openedition
+	exit 0 ;;
     arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
 	echo arm-acorn-riscix${UNAME_RELEASE}
 	exit 0;;
-    arm32:NetBSD:*:*)
-	echo arm-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
-	exit 0 ;;
     SR2?01:HI-UX/MPP:*:*)
 	echo hppa1.1-hitachi-hiuxmpp
 	exit 0;;
@@ -218,15 +303,12 @@ EOF
     aushp:SunOS:*:*)
 	echo sparc-auspex-sunos${UNAME_RELEASE}
 	exit 0 ;;
-    atari*:NetBSD:*:*)
-	echo m68k-atari-netbsd${UNAME_RELEASE}
-	exit 0 ;;
     atari*:OpenBSD:*:*)
 	echo m68k-unknown-openbsd${UNAME_RELEASE}
 	exit 0 ;;
     # The situation for MiNT is a little confusing.  The machine name
     # can be virtually everything (everything which is not
-    # "atarist" or "atariste" at least should have a processor 
+    # "atarist" or "atariste" at least should have a processor
     # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
     # to the lowercase version "mint" (or "freemint").  Finally
     # the system name "TOS" denotes a system which is actually not
@@ -250,15 +332,9 @@ EOF
     *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
         echo m68k-unknown-mint${UNAME_RELEASE}
         exit 0 ;;
-    sun3*:NetBSD:*:*)
-	echo m68k-sun-netbsd${UNAME_RELEASE}
-	exit 0 ;;
     sun3*:OpenBSD:*:*)
 	echo m68k-unknown-openbsd${UNAME_RELEASE}
 	exit 0 ;;
-    mac68k:NetBSD:*:*)
-	echo m68k-apple-netbsd${UNAME_RELEASE}
-	exit 0 ;;
     mac68k:OpenBSD:*:*)
 	echo m68k-unknown-openbsd${UNAME_RELEASE}
 	exit 0 ;;
@@ -271,9 +347,6 @@ EOF
     powerpc:machten:*:*)
 	echo powerpc-apple-machten${UNAME_RELEASE}
 	exit 0 ;;
-    macppc:NetBSD:*:*)
-        echo powerpc-apple-netbsd${UNAME_RELEASE}
-        exit 0 ;;
     RISC*:Mach:*:*)
 	echo mips-dec-mach_bsd4.3
 	exit 0 ;;
@@ -289,6 +362,7 @@ EOF
     mips:*:*:UMIPS | mips:*:*:RISCos)
 	sed 's/^	//' << EOF >$dummy.c
 #ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
 	int main (int argc, char *argv[]) {
 #else
 	int main (argc, argv) int argc; char *argv[]; {
@@ -328,15 +402,18 @@ EOF
     AViiON:dgux:*:*)
         # DG/UX returns AViiON for all architectures
         UNAME_PROCESSOR=`/usr/bin/uname -p`
-        if [ $UNAME_PROCESSOR = mc88100 -o $UNAME_PROCESSOR = mc88110 ] ; then
-	if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx \
-	     -o ${TARGET_BINARY_INTERFACE}x = x ] ; then
+	if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+	then
+	    if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+	       [ ${TARGET_BINARY_INTERFACE}x = x ]
+	    then
 		echo m88k-dg-dgux${UNAME_RELEASE}
-	else
+	    else
 		echo m88k-dg-dguxbcs${UNAME_RELEASE}
+	    fi
+	else
+	    echo i586-dg-dgux${UNAME_RELEASE}
 	fi
-        else echo i586-dg-dgux${UNAME_RELEASE}
-        fi
  	exit 0 ;;
     M88*:DolphinOS:*:*)	# DolphinOS (SVR3)
 	echo m88k-dolphin-sysv3
@@ -402,7 +479,7 @@ EOF
     ibmrt:4.4BSD:*|romp-ibm:BSD:*)
 	echo romp-ibm-bsd4.4
 	exit 0 ;;
-    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC NetBSD and
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
 	echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
 	exit 0 ;;                           # report: romp-ibm BSD 4.3
     *:BOSX:*:*)
@@ -423,6 +500,8 @@ EOF
 	    9000/[34]?? )         HP_ARCH=m68k ;;
 	    9000/[678][0-9][0-9])
               sed 's/^              //' << EOF >$dummy.c
+
+              #define _HPUX_SOURCE
               #include <stdlib.h>
               #include <unistd.h>
 
@@ -453,7 +532,7 @@ EOF
                   exit (0);
               }
 EOF
-	($CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null ) && HP_ARCH=`./$dummy`
+	(CCOPTS= $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null ) && HP_ARCH=`./$dummy`
 	rm -f $dummy.c $dummy
 	esac
 	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
@@ -547,10 +626,13 @@ EOF
 	      -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
 	exit 0 ;;
     CRAY*TS:*:*:*)
-	echo t90-cray-unicos${UNAME_RELEASE}
+	echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
 	exit 0 ;;
     CRAY*T3E:*:*:*)
-	echo alpha-cray-unicosmk${UNAME_RELEASE}
+	echo alpha-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit 0 ;;
+    CRAY*SV1:*:*:*)
+	echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
 	exit 0 ;;
     CRAY-2:*:*:*)
 	echo cray2-cray-unicos
@@ -563,13 +645,10 @@ EOF
     F301:UNIX_System_V:*:*)
        echo f301-fujitsu-uxpv`echo $UNAME_RELEASE | sed 's/ .*//'`
        exit 0 ;;
-    hp3[0-9][05]:NetBSD:*:*)
-	echo m68k-hp-netbsd${UNAME_RELEASE}
-	exit 0 ;;
     hp300:OpenBSD:*:*)
 	echo m68k-unknown-openbsd${UNAME_RELEASE}
 	exit 0 ;;
-    i?86:BSD/386:*:* | i?86:BSD/OS:*:*)
+    i?86:BSD/386:*:* | i?86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
 	echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
 	exit 0 ;;
     sparc*:BSD/OS:*:*)
@@ -579,17 +658,8 @@ EOF
 	echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
 	exit 0 ;;
     *:FreeBSD:*:*)
-	if test -x /usr/bin/objformat; then
-	    if test "elf" = "`/usr/bin/objformat`"; then
-		echo ${UNAME_MACHINE}-unknown-freebsdelf`echo ${UNAME_RELEASE}|sed -e 's/[-_].*//'`
-		exit 0
-	    fi
-	fi
 	echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
 	exit 0 ;;
-    *:NetBSD:*:*)
-	echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
-	exit 0 ;;
     *:OpenBSD:*:*)
 	echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
 	exit 0 ;;
@@ -599,6 +669,9 @@ EOF
     i*:MINGW*:*)
 	echo ${UNAME_MACHINE}-pc-mingw32
 	exit 0 ;;
+    i*:PW*:*)
+	echo ${UNAME_MACHINE}-pc-pw32
+	exit 0 ;;
     i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
 	# How do we know it's Interix rather than the generic POSIX subsystem?
 	# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
@@ -617,13 +690,10 @@ EOF
     *:GNU:*:*)
 	echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
 	exit 0 ;;
+    i*86:Minix:*:*)
+	echo ${UNAME_MACHINE}-pc-minix
+	exit 0 ;;
     *:Linux:*:*)
-	# uname on the ARM produces all sorts of strangeness, and we need to
-	# filter it out.
-	case "$UNAME_MACHINE" in
-	  armv*)		      UNAME_MACHINE=$UNAME_MACHINE ;;
-	  arm* | sa110*)	      UNAME_MACHINE="arm" ;;
-	esac
 
 	# The BFD linker knows what the default object file format is, so
 	# first see if it will tell us. cd to the root directory to prevent
@@ -636,12 +706,41 @@ EOF
 				    s/ .*//
 				    p'`
         case "$ld_supported_emulations" in
-	  *ia64)      echo "${UNAME_MACHINE}-unknown-linux"         ; exit 0 ;;
-	  i?86linux)  echo "${UNAME_MACHINE}-pc-linux-gnuaout"      ; exit 0 ;;
-	  i?86coff)   echo "${UNAME_MACHINE}-pc-linux-gnucoff"      ; exit 0 ;;
-	  sparclinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;;
-	  armlinux)   echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;;
-	  m68klinux)  echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;;
+	  *ia64)
+		echo "${UNAME_MACHINE}-unknown-linux"
+		exit 0
+		;;
+	  i?86linux)
+		echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+		exit 0
+		;;
+	  elf_i?86)
+		TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+		;;
+	  i?86coff)
+		echo "${UNAME_MACHINE}-pc-linux-gnucoff"
+		exit 0
+		;;
+	  sparclinux)
+		echo "${UNAME_MACHINE}-unknown-linux-gnuaout"
+		exit 0
+		;;
+	  armlinux)
+		echo "${UNAME_MACHINE}-unknown-linux-gnuaout"
+		exit 0
+		;;
+	  elf32arm*)
+		echo "${UNAME_MACHINE}-unknown-linux-gnuoldld"
+		exit 0
+		;;
+	  armelf_linux*)
+		echo "${UNAME_MACHINE}-unknown-linux-gnu"
+		exit 0
+		;;
+	  m68klinux)
+		echo "${UNAME_MACHINE}-unknown-linux-gnuaout"
+		exit 0
+		;;
 	  elf32ppc | elf32ppclinux)
 		# Determine Lib Version
 		cat >$dummy.c <<EOF
@@ -669,49 +768,65 @@ EOF
 			if test "$?" = 0 ; then
 				LIBC="libc1"
 			fi
-		fi	
+		fi
 		rm -f $dummy.c $dummy
-		echo powerpc-unknown-linux-gnu${LIBC} ; exit 0 ;;
+		echo powerpc-unknown-linux-gnu${LIBC}
+		exit 0
+		;;
+	  shelf_linux)
+		echo "${UNAME_MACHINE}-unknown-linux-gnu"
+		exit 0
+		;;
 	esac
 
 	if test "${UNAME_MACHINE}" = "alpha" ; then
-		sed 's/^	//'  <<EOF >$dummy.s
-		.globl main
-		.ent main
-	main:
-		.frame \$30,0,\$26,0
-		.prologue 0
-		.long 0x47e03d80 # implver $0
-		lda \$2,259
-		.long 0x47e20c21 # amask $2,$1
-		srl \$1,8,\$2
-		sll \$2,2,\$2
-		sll \$0,3,\$0
-		addl \$1,\$0,\$0
-		addl \$2,\$0,\$0
-		ret \$31,(\$26),1
-		.end main
+		cat <<EOF >$dummy.s
+			.data
+		\$Lformat:
+			.byte 37,100,45,37,120,10,0	# "%d-%x\n"
+
+			.text
+			.globl main
+			.align 4
+			.ent main
+		main:
+			.frame \$30,16,\$26,0
+			ldgp \$29,0(\$27)
+			.prologue 1
+			.long 0x47e03d80 # implver \$0
+			lda \$2,-1
+			.long 0x47e20c21 # amask \$2,\$1
+			lda \$16,\$Lformat
+			mov \$0,\$17
+			not \$1,\$18
+			jsr \$26,printf
+			ldgp \$29,0(\$26)
+			mov 0,\$16
+			jsr \$26,exit
+			.end main
 EOF
 		LIBC=""
 		$CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null
 		if test "$?" = 0 ; then
-			./$dummy
-			case "$?" in
-			7)
+			case `./$dummy` in
+			0-0)
 				UNAME_MACHINE="alpha"
 				;;
-			15)
+			1-0)
 				UNAME_MACHINE="alphaev5"
 				;;
-			14)
+			1-1)
 				UNAME_MACHINE="alphaev56"
 				;;
-			10)
+			1-101)
 				UNAME_MACHINE="alphapca56"
 				;;
-			16)
+			2-303)
 				UNAME_MACHINE="alphaev6"
 				;;
+			2-307)
+				UNAME_MACHINE="alphaev67"
+				;;
 			esac
 
 			objdump --private-headers $dummy | \
@@ -725,6 +840,7 @@ EOF
 	elif test "${UNAME_MACHINE}" = "mips" ; then
 	  cat >$dummy.c <<EOF
 #ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
 	int main (int argc, char *argv[]) {
 #else
 	int main (argc, argv) int argc; char *argv[]; {
@@ -740,6 +856,24 @@ EOF
 EOF
 	  $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0
 	  rm -f $dummy.c $dummy
+	elif test "${UNAME_MACHINE}" = "s390"; then
+	  echo s390-ibm-linux && exit 0
+	elif test "${UNAME_MACHINE}" = "x86_64"; then
+	  echo x86_64-unknown-linux-gnu && exit 0
+	elif test "${UNAME_MACHINE}" = "parisc" -o "${UNAME_MACHINE}" = "hppa"; then
+	  # Look for CPU level
+	  case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+	    PA7*)
+		echo hppa1.1-unknown-linux-gnu
+		;;
+	    PA8*)
+		echo hppa2.0-unknown-linux-gnu
+		;;
+	    *)
+		echo hppa-unknown-linux-gnu
+		;;
+	  esac
+	  exit 0;
 	else
 	  # Either a pre-BFD a.out linker (linux-gnuoldld)
 	  # or one that does not give us useful --help.
@@ -761,6 +895,7 @@ EOF
 	  cat >$dummy.c <<EOF
 #include <features.h>
 #ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
 	int main (int argc, char *argv[]) {
 #else
 	int main (argc, argv) int argc; char *argv[]; {
@@ -783,6 +918,7 @@ EOF
 EOF
 	  $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0
 	  rm -f $dummy.c $dummy
+	  test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0
 	fi ;;
 # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.  earlier versions
 # are messed up and put the nodename in both sysname and nodename.
@@ -798,19 +934,21 @@ EOF
 	echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
 	exit 0 ;;
     i?86:*:4.*:* | i?86:SYSTEM_V:4.*:*)
+	UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
 	if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
-		echo ${UNAME_MACHINE}-univel-sysv${UNAME_RELEASE}
+		echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
 	else
-		echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE}
+		echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
 	fi
 	exit 0 ;;
     i?86:*:5:7*)
-	UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
-	(/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
-	(/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) && UNAME_MACHINE=i586
-	(/bin/uname -X|egrep '^Machine.*Pent.*II' >/dev/null) && UNAME_MACHINE=i686
-	(/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) && UNAME_MACHINE=i585
-	echo ${UNAME_MACHINE}-${UNAME_SYSTEM}${UNAME_VERSION}-sysv${UNAME_RELEASE}
+        # Fixed at (any) Pentium or better
+        UNAME_MACHINE=i586
+        if [ ${UNAME_SYSTEM} = "UnixWare" ] ; then
+	    echo ${UNAME_MACHINE}-sco-sysv${UNAME_RELEASE}uw${UNAME_VERSION}
+	else
+	    echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE}
+	fi
 	exit 0 ;;
     i?86:*:3.2:*)
 	if test -f /usr/options/cb.name; then
@@ -830,7 +968,11 @@ EOF
 		echo ${UNAME_MACHINE}-pc-sysv32
 	fi
 	exit 0 ;;
+    i?86:*DOS:*:*)
+	echo ${UNAME_MACHINE}-pc-msdosdjgpp
+	exit 0 ;;
     pc:*:*:*)
+	# Left here for compatibility:
         # uname -m prints for DJGPP always 'pc', but it prints nothing about
         # the processor, so we play safe by assuming i386.
 	echo i386-pc-msdosdjgpp
@@ -913,7 +1055,7 @@ EOF
     mc68*:A/UX:*:*)
 	echo m68k-apple-aux${UNAME_RELEASE}
 	exit 0 ;;
-    news*:NEWS-OS:*:6*)
+    news*:NEWS-OS:6*:*)
 	echo mips-sony-newsos6
 	exit 0 ;;
     R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
@@ -944,6 +1086,38 @@ EOF
     *:Rhapsody:*:*)
 	echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
 	exit 0 ;;
+    *:Darwin:*:*)
+	echo `uname -p`-apple-darwin${UNAME_RELEASE}
+	exit 0 ;;
+    *:procnto*:*:* | *:QNX:[0123456789]*:*)
+	if test "${UNAME_MACHINE}" = "x86pc"; then
+		UNAME_MACHINE=pc
+	fi
+	echo `uname -p`-${UNAME_MACHINE}-nto-qnx
+	exit 0 ;;
+    *:QNX:*:4*)
+	echo i386-pc-qnx
+	exit 0 ;;
+    NSR-[KW]:NONSTOP_KERNEL:*:*)
+	echo nsr-tandem-nsk${UNAME_RELEASE}
+	exit 0 ;;
+    BS2000:POSIX*:*:*)
+	echo bs2000-siemens-sysv
+	exit 0 ;;
+    DS/*:UNIX_System_V:*:*)
+	echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+	exit 0 ;;
+    *:Plan9:*:*)
+	# "uname -m" is not consistent, so use $cputype instead. 386
+	# is converted to i386 for consistency with other x86
+	# operating systems.
+	if test "$cputype" = "386"; then
+	    UNAME_MACHINE=i386
+	else
+	    UNAME_MACHINE="$cputype"
+	fi
+	echo ${UNAME_MACHINE}-unknown-plan9
+	exit 0 ;;
 esac
 
 #echo '(No uname command or uname output not recognized.)' 1>&2
@@ -1083,6 +1257,47 @@ then
     esac
 fi
 
-#echo '(Unable to guess system type)' 1>&2
+cat >&2 <<EOF
+$0: unable to guess system type
+
+The $version version of this script cannot recognize your system type.
+Please download the most up to date version of the config scripts:
+
+    ftp://ftp.gnu.org/pub/gnu/config/
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess version = $version
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo               = `(hostinfo) 2>/dev/null`
+/bin/universe          = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch              = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM  = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
 
 exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "version='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:

+ 5 - 11
buildlib/config.h.in

@@ -16,15 +16,6 @@
 /* The number of bytes in a unsigned short.  */
 #undef SIZEOF_SHORT
 
-/* Define if we have libgpm. */
-#undef HAVE_LIBGPM
-
-/* Define if we have the SLang library from Davis. */
-#undef HAVE_LIBSLANG    
-
-/* Define if we have the X11 windowing system. */
-#undef HAVE_X11
-
 /* These two are used by the statvfs shim for glibc2.0 and bsd */
 /* Define if we have sys/vfs.h */
 #undef HAVE_VFS_H
@@ -38,8 +29,11 @@
 /* If there is no socklen_t, define this for the netdb shim */
 #undef NEED_SOCKLEN_T_DEFINE
 
-/* Define the architecture name string */
-#undef ARCHITECTURE
+/* Define the cpu name string */
+#undef COMMON_CPU
+
+/* Define the on name string */
+#undef COMMON_OS
 
 /* The version number string */
 #undef VERSION

+ 0 - 0
buildlib/config.sub


Some files were not shown because too many files changed in this diff