summaryrefslogtreecommitdiff
path: root/apt-pkg
diff options
context:
space:
mode:
authorArch Librarian <arch@canonical.com>2004-09-20 16:50:36 +0000
committerArch Librarian <arch@canonical.com>2004-09-20 16:50:36 +0000
commit578bfd0aed2ec993f4ad85fa6a7094a852261422 (patch)
tree737f52267f6468a4b6754f8c6665824767352746 /apt-pkg
downloadapt-578bfd0aed2ec993f4ad85fa6a7094a852261422.tar.gz
Base revisions
Author: jgg Date: 1998-07-02 02:58:12 GMT Base revisions
Diffstat (limited to 'apt-pkg')
-rw-r--r--apt-pkg/cacheiterators.h281
-rw-r--r--apt-pkg/contrib/error.cc139
-rw-r--r--apt-pkg/contrib/error.h84
-rw-r--r--apt-pkg/contrib/fileutl.cc214
-rw-r--r--apt-pkg/contrib/fileutl.h63
-rw-r--r--apt-pkg/contrib/mmap.cc227
-rw-r--r--apt-pkg/contrib/mmap.h92
-rw-r--r--apt-pkg/contrib/system.h57
-rw-r--r--apt-pkg/pkgcache.cc360
-rw-r--r--apt-pkg/pkgcache.h280
-rw-r--r--apt-pkg/pkgcachegen.cc184
-rw-r--r--apt-pkg/pkgcachegen.h69
-rw-r--r--apt-pkg/tagfile.cc195
-rw-r--r--apt-pkg/tagfile.h64
-rw-r--r--apt-pkg/version.cc249
-rw-r--r--apt-pkg/version.h45
16 files changed, 2603 insertions, 0 deletions
diff --git a/apt-pkg/cacheiterators.h b/apt-pkg/cacheiterators.h
new file mode 100644
index 000000000..539444c33
--- /dev/null
+++ b/apt-pkg/cacheiterators.h
@@ -0,0 +1,281 @@
+// -*- mode: cpp; mode: fold -*-
+// Description /*{{{*/
+// $Id: cacheiterators.h,v 1.1 1998/07/02 02:58:12 jgg Exp $
+/* ######################################################################
+
+ Cache Iterators - Iterators for navigating the cache structure
+
+ The iterators all provides ++,==,!=,->,* and end for their type.
+ The end function can be used to tell if the list has been fully
+ traversed.
+
+ Unlike STL iterators these contain helper functions to access the data
+ that is being iterated over. This is because the data structures can't
+ be formed in a manner that is intuitive to use and also mmapable.
+
+ For each variable in the target structure that would need a translation
+ to be accessed correctly a translating function of the same name is
+ present in the iterator. If applicable the translating function will
+ return an iterator.
+
+ The DepIterator can iterate over two lists, a list of 'version depends'
+ or a list of 'package reverse depends'. The type is determined by the
+ structure passed to the constructor, which should be the structure
+ that has the depends pointer as a member.
+
+ This header is not user includable, please use pkglib/pkgcache.h
+
+ ##################################################################### */
+ /*}}}*/
+// Header section: pkglib
+#ifndef PKGLIB_CACHEITERATORS_H
+#define PKGLIB_CACHEITERATORS_H
+
+// Package Iterator
+class pkgCache::PkgIterator
+{
+ Package *Pkg;
+ pkgCache *Owner;
+ long HashIndex;
+
+ public:
+
+ enum OkState {NeedsNothing,NeedsUnpack,NeedsConfigure};
+
+ // Iteration
+ void operator ++(int);
+ inline void operator ++() {operator ++(0);};
+ inline bool end() const {return Owner == 0 || Pkg == Owner->PkgP?true:false;};
+
+ // Comparison
+ inline bool operator ==(const PkgIterator &B) const {return Pkg == B.Pkg;};
+ inline bool operator !=(const PkgIterator &B) const {return Pkg != B.Pkg;};
+
+ // 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 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 VerIterator VersionList() const;
+ inline VerIterator TargetVer() const;
+ inline VerIterator CurrentVer() const;
+ inline DepIterator RevDependsList() const;
+ inline PrvIterator ProvidesList() const;
+ 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)
+ {
+ if (Pkg == 0)
+ Pkg = Owner.PkgP;
+ };
+ inline PkgIterator() : Pkg(0), Owner(0), HashIndex(0) {};
+};
+
+// Version Iterator
+class pkgCache::VerIterator
+{
+ Version *Ver;
+ pkgCache &Owner;
+
+ void _dummy();
+
+ public:
+
+ // Iteration
+ void operator ++(int) {if (Ver != Owner.VerP) Ver = Owner.VerP + Ver->NextVer;};
+ inline void operator ++() {operator ++(0);};
+ inline bool end() const {return Ver == Owner.VerP?true:false;};
+ inline void operator =(const VerIterator &B) {Ver = B.Ver;};
+
+ // Comparison
+ inline bool operator ==(const VerIterator &B) const {return Ver == B.Ver;};
+ inline bool operator !=(const VerIterator &B) const {return Ver != B.Ver;};
+ int CompareVer(const VerIterator &B) const;
+
+ // Accessors
+ inline Version *operator ->() {return Ver;};
+ inline Version const *operator ->() const {return Ver;};
+ inline Version &operator *() {return *Ver;};
+ inline Version const &operator *() const {return *Ver;};
+ inline operator Version *() {return Ver == Owner.VerP?0:Ver;};
+ inline operator Version const *() const {return Ver == Owner.VerP?0:Ver;};
+ inline const char *VerStr() const {return Ver->VerStr == 0?0:Owner.StrP + Ver->VerStr;};
+ inline const char *Section() const {return Ver->Section == 0?0:Owner.StrP + Ver->Section;};
+ inline PkgFileIterator File() const;
+ inline PkgIterator ParentPkg() const {return PkgIterator(Owner,Owner.PkgP + Ver->ParentPkg);};
+ inline DepIterator DependsList() const;
+ inline PrvIterator ProvidesList() const;
+
+ inline VerIterator(pkgCache &Owner,Version *Trg) : Ver(Trg), Owner(Owner)
+ {
+ if (Ver == 0)
+ Ver = Owner.VerP;
+ };
+};
+
+// Dependency iterator
+class pkgCache::DepIterator
+{
+ Dependency *Dep;
+ enum {DepVer, DepRev} Type;
+ pkgCache *Owner;
+
+ void _dummy();
+
+ public:
+
+ // Iteration
+ void operator ++(int) {if (Dep != Owner->DepP) Dep = Owner->DepP +
+ (Type == DepVer?Dep->NextDepends:Dep->NextRevDepends);};
+ inline void operator ++() {operator ++(0);};
+ inline bool end() const {return Owner == 0 || Dep == Owner->DepP?true:false;};
+
+ // Comparison
+ inline bool operator ==(const DepIterator &B) const {return Dep == B.Dep;};
+ inline bool operator !=(const DepIterator &B) const {return Dep != B.Dep;};
+
+ // Accessors
+ inline Dependency *operator ->() {return Dep;};
+ inline Dependency const *operator ->() const {return Dep;};
+ inline Dependency &operator *() {return *Dep;};
+ inline Dependency const &operator *() const {return *Dep;};
+ inline operator Dependency *() {return Dep == Owner->DepP?0:Dep;};
+ inline operator Dependency const *() const {return Dep == Owner->DepP?0:Dep;};
+ inline const char *TargetVer() const {return Dep->Version == 0?0:Owner->StrP + Dep->Version;};
+ inline PkgIterator TargetPkg() {return PkgIterator(*Owner,Owner->PkgP + Dep->Package);};
+ Version **AllTargets();
+ bool SmartTargetPkg(PkgIterator &Result);
+ inline PkgIterator SmartTargetPkg() {PkgIterator R(*Owner);SmartTargetPkg(R);return R;};
+ inline VerIterator ParentVer() {return VerIterator(*Owner,Owner->VerP + Dep->ParentVer);};
+ inline PkgIterator ParentPkg() {return PkgIterator(*Owner,Owner->PkgP + Owner->VerP[Dep->ParentVer].ParentPkg);};
+ bool IsCritical();
+ inline bool Reverse() {return Type == DepRev;};
+
+ inline DepIterator(pkgCache &Owner,Dependency *Trg,Version * = 0) :
+ Dep(Trg), Type(DepVer), Owner(&Owner)
+ {
+ if (Dep == 0)
+ Dep = Owner.DepP;
+ };
+ inline DepIterator(pkgCache &Owner,Dependency *Trg,Package *) :
+ Dep(Trg), Type(DepRev), Owner(&Owner)
+ {
+ if (Dep == 0)
+ Dep = Owner.DepP;
+ };
+ inline DepIterator() : Dep(0), Type(DepVer), Owner(0) {};
+};
+
+// Provides iterator
+class pkgCache::PrvIterator
+{
+ Provides *Prv;
+ enum {PrvVer, PrvPkg} Type;
+ pkgCache *Owner;
+
+ void _dummy();
+
+ public:
+
+ // Iteration
+ void operator ++(int) {if (Prv != Owner->ProvideP) Prv = Owner->ProvideP +
+ (Type == PrvVer?Prv->NextPkgProv:Prv->NextProvides);};
+ inline void operator ++() {operator ++(0);};
+ inline bool end() const {return Prv == Owner->ProvideP?true:false;};
+
+ // Comparison
+ inline bool operator ==(const PrvIterator &B) const {return Prv == B.Prv;};
+ inline bool operator !=(const PrvIterator &B) const {return Prv != B.Prv;};
+
+ // Accessors
+ inline Provides *operator ->() {return Prv;};
+ inline Provides const *operator ->() const {return Prv;};
+ inline Provides &operator *() {return *Prv;};
+ inline Provides const &operator *() const {return *Prv;};
+ inline operator Provides *() {return Prv == Owner->ProvideP?0:Prv;};
+ inline operator Provides const *() const {return Prv == Owner->ProvideP?0:Prv;};
+ inline const char *Name() const {return Owner->StrP + Owner->PkgP[Prv->ParentPkg].Name;};
+ inline const char *ProvideVersion() const {return Prv->ProvideVersion == 0?0:Owner->StrP + Prv->ProvideVersion;};
+ inline PkgIterator ParentPkg() {return PkgIterator(*Owner,Owner->PkgP + Prv->ParentPkg);};
+ inline VerIterator OwnerVer() {return VerIterator(*Owner,Owner->VerP + Prv->Version);};
+ inline PkgIterator OwnerPkg() {return PkgIterator(*Owner,Owner->PkgP + Owner->VerP[Prv->Version].ParentPkg);};
+
+ inline PrvIterator(pkgCache &Owner,Provides *Trg,Version *) :
+ Prv(Trg), Type(PrvVer), Owner(&Owner)
+ {
+ if (Prv == 0)
+ Prv = Owner.ProvideP;
+ };
+ inline PrvIterator(pkgCache &Owner,Provides *Trg,Package *) :
+ Prv(Trg), Type(PrvPkg), Owner(&Owner)
+ {
+ if (Prv == 0)
+ Prv = Owner.ProvideP;
+ };
+};
+
+// Package file
+class pkgCache::PkgFileIterator
+{
+ pkgCache *Owner;
+ PackageFile *File;
+
+ public:
+
+ // Iteration
+ void operator ++(int) {if (File!= Owner->PkgFileP) File = Owner->PkgFileP + File->NextFile;};
+ inline void operator ++() {operator ++(0);};
+ inline bool end() const {return File == Owner->PkgFileP?true:false;};
+
+ // Comparison
+ inline bool operator ==(const PkgFileIterator &B) const {return File == B.File;};
+ inline bool operator !=(const PkgFileIterator &B) const {return File != B.File;};
+
+ // Accessors
+ inline PackageFile *operator ->() {return File;};
+ inline PackageFile const *operator ->() const {return File;};
+ 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 const char *FileName() const {return File->FileName == 0?0:Owner->StrP + File->FileName;};
+ inline const char *Version() const {return File->Version == 0?0:Owner->StrP + File->Version;};
+ inline const char *Distribution() const {return File->Distribution == 0?0:Owner->StrP + File->Distribution;};
+
+ bool IsOk();
+
+ // Constructors
+ inline PkgFileIterator(pkgCache &Owner) : Owner(&Owner), File(Owner.PkgFileP + Owner.Head().FileList) {};
+ inline PkgFileIterator(pkgCache &Owner,PackageFile *Trg) : Owner(&Owner), File(Trg) {};
+};
+
+// Inlined Begin functions cant be in the class because of order problems
+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
+ {return PrvIterator(*Owner,Owner->ProvideP + Pkg->ProvidesList,Pkg);};
+inline pkgCache::PrvIterator pkgCache::VerIterator::ProvidesList() const
+ {return PrvIterator(Owner,Owner.ProvideP + Ver->ProvidesList,Ver);};
+inline pkgCache::DepIterator pkgCache::VerIterator::DependsList() const
+ {return DepIterator(Owner,Owner.DepP + Ver->DependsList,Ver);};
+inline pkgCache::PkgFileIterator pkgCache::VerIterator::File() const
+ {return PkgFileIterator(Owner,Owner.PkgFileP + Ver->File);};
+
+#endif
diff --git a/apt-pkg/contrib/error.cc b/apt-pkg/contrib/error.cc
new file mode 100644
index 000000000..59d2b8c8b
--- /dev/null
+++ b/apt-pkg/contrib/error.cc
@@ -0,0 +1,139 @@
+// -*- mode: cpp; mode: fold -*-
+// Description /*{{{*/
+// $Id: error.cc,v 1.1 1998/07/02 02:58:13 jgg Exp $
+/* ######################################################################
+
+ Global Erorr Class - Global error mechanism
+
+ We use a simple STL vector to store each error record. A PendingFlag
+ is kept which indicates when the vector contains a Sever error.
+
+ This source is placed in the Public Domain, do with it what you will
+ It was originally written by Jason Gunthorpe.
+
+ ##################################################################### */
+ /*}}}*/
+// Include Files /*{{{*/
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include <pkglib/error.h>
+ /*}}}*/
+
+GlobalError *_error = new GlobalError;
+
+// GlobalError::GlobalError - Constructor /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+GlobalError::GlobalError() : PendingFlag(false)
+{
+}
+ /*}}}*/
+// GlobalError::Errno - Get part of the error string from errno /*{{{*/
+// ---------------------------------------------------------------------
+/* Function indicates the stdlib function that failed and Description is
+ a user string that leads the text. Form is:
+ Description - Function (errno: strerror)
+ Carefull of the buffer overrun, sprintf.
+ */
+bool GlobalError::Errno(const char *Function,const char *Description,...)
+{
+ va_list args;
+ va_start(args,Description);
+
+ // sprintf the description
+ char S[400];
+ vsprintf(S,Description,args);
+ sprintf(S + strlen(S)," - %s (%i %s)",Function,errno,strerror(errno));
+
+ // Put it on the list
+ Item Itm;
+ Itm.Text = S;
+ Itm.Error = true;
+ List.push_back(Itm);
+
+ PendingFlag = true;
+
+ return false;
+}
+ /*}}}*/
+// GlobalError::Error - Add an error to the list /*{{{*/
+// ---------------------------------------------------------------------
+/* Just vsprintfs and pushes */
+bool GlobalError::Error(const char *Description,...)
+{
+ va_list args;
+ va_start(args,Description);
+
+ // sprintf the description
+ char S[400];
+ vsprintf(S,Description,args);
+
+ // Put it on the list
+ Item Itm;
+ Itm.Text = S;
+ Itm.Error = true;
+ List.push_back(Itm);
+
+ PendingFlag = true;
+
+ return false;
+}
+ /*}}}*/
+// GlobalError::Warning - Add a warning to the list /*{{{*/
+// ---------------------------------------------------------------------
+/* This doesn't set the pending error flag */
+bool GlobalError::Warning(const char *Description,...)
+{
+ va_list args;
+ va_start(args,Description);
+
+ // sprintf the description
+ char S[400];
+ vsprintf(S,Description,args);
+
+ // Put it on the list
+ Item Itm;
+ Itm.Text = S;
+ Itm.Error = false;
+ List.push_back(Itm);
+
+ return false;
+}
+ /*}}}*/
+// GlobalError::PopMessage - Pulls a single message out /*{{{*/
+// ---------------------------------------------------------------------
+/* This should be used in a loop checking empty() each cycle. It returns
+ true if the message is an error. */
+bool GlobalError::PopMessage(string &Text)
+{
+ bool Ret = List.front().Error;
+ Text = List.front().Text;
+ List.erase(List.begin());
+
+ // This really should check the list to see if only warnings are left..
+ if (empty())
+ PendingFlag = false;
+
+ return Ret;
+}
+ /*}}}*/
+// GlobalError::DumpErrors - Dump all of the errors/warns to cerr /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+void GlobalError::DumpErrors()
+{
+ // Print any errors or warnings found
+ string Err;
+ while (empty() == false)
+ {
+ bool Type = PopMessage(Err);
+ if (Type == true)
+ cerr << "E: " << Err << endl;
+ else
+ cerr << "W: " << Err << endl;
+ }
+}
+ /*}}}*/
diff --git a/apt-pkg/contrib/error.h b/apt-pkg/contrib/error.h
new file mode 100644
index 000000000..06b998e5e
--- /dev/null
+++ b/apt-pkg/contrib/error.h
@@ -0,0 +1,84 @@
+// -*- mode: cpp; mode: fold -*-
+// Description /*{{{*/
+// $Id: error.h,v 1.1 1998/07/02 02:58:13 jgg Exp $
+/* ######################################################################
+
+ Global Erorr Class - Global error mechanism
+
+ This class has a single global instance. When a function needs to
+ generate an error condition, such as a read error, it calls a member
+ in this class to add the error to a stack of errors.
+
+ By using a stack the problem with a scheme like errno is removed and
+ it allows a very detailed account of what went wrong to be transmitted
+ to the UI for display. (Errno has problems because each function sets
+ errno to 0 if it didn't have an error thus eraseing erno in the process
+ of cleanup)
+
+ Several predefined error generators are provided to handle common
+ things like errno. The general idea is that all methods return a bool.
+ If the bool is true then things are OK, if it is false then things
+ should start being undone and the stack should unwind under program
+ control.
+
+ A Warning should not force the return of false. Things did not fail, but
+ they might have had unexpected problems. Errors are stored in a FIFO
+ so Pop will return the first item..
+
+ I have some thoughts about extending this into a more general UI<->
+ Engine interface, ie allowing the Engine to say 'The disk is full' in
+ a dialog that says 'Panic' and 'Retry'.. The error generator functions
+ like errno, Warning and Error return false always so this is normal:
+ if (open(..))
+ return _error->Errno(..);
+
+ This source is placed in the Public Domain, do with it what you will
+ It was originally written by Jason Gunthorpe.
+
+ ##################################################################### */
+ /*}}}*/
+// Header section: pkglib
+#ifndef PKGLIB_ERROR_H
+#define PKGLIB_ERROR_H
+
+#include <string>
+#include <vector.h>
+
+class GlobalError
+{
+ struct Item
+ {
+ string Text;
+ bool Error;
+ };
+
+ vector<Item> List;
+ bool PendingFlag;
+
+ public:
+
+ // Call to generate an error from a library call.
+ bool Errno(const char *Function,const char *Description,...);
+
+ /* 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,...);
+
+ // Simple accessors
+ inline bool PendingError() {return PendingFlag;};
+ inline bool empty() {return List.empty();};
+ bool PopMessage(string &Text);
+ void Discard() {List.erase(List.begin(),List.end()); PendingFlag = false;};
+
+ // Usefull routine to dump to cerr
+ void DumpErrors();
+
+ GlobalError();
+};
+
+/* The 'extra-ansi' syntax is used to help with collisions. This is the
+ single global instance of this class. */
+extern GlobalError *_error;
+
+#endif
diff --git a/apt-pkg/contrib/fileutl.cc b/apt-pkg/contrib/fileutl.cc
new file mode 100644
index 000000000..6048ff0bb
--- /dev/null
+++ b/apt-pkg/contrib/fileutl.cc
@@ -0,0 +1,214 @@
+// -*- mode: cpp; mode: fold -*-
+// Description /*{{{*/
+// $Id: fileutl.cc,v 1.1 1998/07/02 02:58:13 jgg Exp $
+/* ######################################################################
+
+ File Utilities
+
+ CopyFile - Buffered copy of a single file
+ GetLock - dpkg compatible lock file manipulation (fcntl)
+
+ This source is placed in the Public Domain, do with it what you will
+ It was originally written by Jason Gunthorpe.
+
+ ##################################################################### */
+ /*}}}*/
+// Include Files /*{{{*/
+#include <fileutl.h>
+#include <pkglib/error.h>
+
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/fcntl.h>
+#include <sys/types.h>
+ /*}}}*/
+
+// CopyFile - Buffered copy of a file /*{{{*/
+// ---------------------------------------------------------------------
+/* The caller is expected to set things so that failure causes erasure */
+bool CopyFile(File From,File To)
+{
+ if (From.IsOpen() == false || To.IsOpen() == false)
+ return false;
+
+ // Buffered copy between fds
+ unsigned char *Buf = new unsigned char[64000];
+ long Size;
+ while ((Size = read(From.Fd(),Buf,64000)) > 0)
+ {
+ if (To.Write(Buf,Size) == false)
+ {
+ delete [] Buf;
+ return false;
+ }
+ }
+
+ delete [] Buf;
+ return true;
+}
+ /*}}}*/
+// GetLock - Gets a lock file /*{{{*/
+// ---------------------------------------------------------------------
+/* This will create an empty file of the given name and lock it. Once this
+ is done all other calls to GetLock in any other process will fail with
+ -1. The return result is the fd of the file, the call should call
+ close at some time. */
+int GetLock(string File,bool Errors)
+{
+ int FD = open(File.c_str(),O_RDWR | O_CREAT | O_TRUNC,0640);
+ if (FD < 0)
+ {
+ if (Errors == true)
+ _error->Errno("open","Could not open lock file %s",File.c_str());
+ return -1;
+ }
+
+ // Aquire a write lock
+ struct flock fl;
+ fl.l_type= F_WRLCK;
+ fl.l_whence= SEEK_SET;
+ fl.l_start= 0;
+ fl.l_len= 1;
+ if (fcntl(FD,F_SETLK,&fl) == -1)
+ {
+ if (Errors == true)
+ _error->Errno("open","Could not get lock %s",File.c_str());
+ close(FD);
+ return -1;
+ }
+
+ return FD;
+}
+ /*}}}*/
+// FileExists - Check if a file exists /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool FileExists(string File)
+{
+ struct stat Buf;
+ if (stat(File.c_str(),&Buf) != 0)
+ return false;
+ return true;
+}
+ /*}}}*/
+// SafeGetCWD - This is a safer getcwd that returns a dynamic string /*{{{*/
+// ---------------------------------------------------------------------
+/* We return / on failure. */
+string SafeGetCWD()
+{
+ // Stash the current dir.
+ char S[300];
+ S[0] = 0;
+ if (getcwd(S,sizeof(S)) == 0)
+ return "/";
+ return S;
+}
+ /*}}}*/
+
+// File::File - Open a file /*{{{*/
+// ---------------------------------------------------------------------
+/* The most commonly used open mode combinations are given with Mode */
+File::File(string FileName,OpenMode Mode, unsigned long Perms)
+{
+ Flags = 0;
+ switch (Mode)
+ {
+ case ReadOnly:
+ iFd = open(FileName.c_str(),O_RDONLY);
+ break;
+
+ case WriteEmpty:
+ unlink(FileName.c_str());
+ iFd = open(FileName.c_str(),O_RDWR | O_CREAT | O_EXCL,Perms);
+ break;
+
+ case WriteExists:
+ iFd = open(FileName.c_str(),O_RDWR);
+ break;
+ }
+
+ if (iFd < 0)
+ _error->Errno("open","Could not open file %s",FileName.c_str());
+ else
+ this->FileName = FileName;
+}
+ /*}}}*/
+// File::~File - Closes the file /*{{{*/
+// ---------------------------------------------------------------------
+/* If the proper modes are selected then we close the Fd and possibly
+ unlink the file on error. */
+File::~File()
+{
+ Close();
+}
+ /*}}}*/
+// File::Read - Read a bit of the file /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool File::Read(void *To,unsigned long Size)
+{
+ if (read(iFd,To,Size) != (signed)Size)
+ {
+ Flags |= Fail;
+ return _error->Errno("read","Read error");
+ }
+
+ return true;
+}
+ /*}}}*/
+// File::Write - Write to the file /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool File::Write(void *From,unsigned long Size)
+{
+ if (write(iFd,From,Size) != (signed)Size)
+ {
+ Flags |= Fail;
+ return _error->Errno("write","Write error");
+ }
+
+ return true;
+}
+ /*}}}*/
+// File::Seek - Seek in the file /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool File::Seek(unsigned long To)
+{
+ if (lseek(iFd,To,SEEK_SET) != (signed)To)
+ {
+ Flags |= Fail;
+ return _error->Error("Unable to seek to %u",To);
+ }
+
+ return true;
+}
+ /*}}}*/
+// File::Size - Return the size of the file /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+unsigned long File::Size()
+{
+ struct stat Buf;
+ if (fstat(iFd,&Buf) != 0)
+ return _error->Errno("fstat","Unable to determine the file size");
+ return Buf.st_size;
+}
+ /*}}}*/
+// File::Close - Close the file if the close flag is set /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool File::Close()
+{
+ bool Res = true;
+ if ((Flags & AutoClose) == AutoClose)
+ if (close(iFd) != 0)
+ Res &= _error->Errno("close","Problem closing the file");
+
+ if ((Flags & Fail) == Fail && (Flags & DelOnFail) == DelOnFail &&
+ FileName.empty() == false)
+ if (unlink(FileName.c_str()) != 0)
+ Res &= _error->Warning("unlnk","Problem unlinking the file");
+ return Res;
+}
+ /*}}}*/
diff --git a/apt-pkg/contrib/fileutl.h b/apt-pkg/contrib/fileutl.h
new file mode 100644
index 000000000..1b6666843
--- /dev/null
+++ b/apt-pkg/contrib/fileutl.h
@@ -0,0 +1,63 @@
+// -*- mode: cpp; mode: fold -*-
+// Description /*{{{*/
+// $Id: fileutl.h,v 1.1 1998/07/02 02:58:13 jgg Exp $
+/* ######################################################################
+
+ File Utilities
+
+ CopyFile - Buffered copy of a single file
+ GetLock - dpkg compatible lock file manipulation (fcntl)
+ FileExists - Returns true if the file exists
+ SafeGetCWD - Returns the CWD in a string with overrun protection
+
+ The file class is a handy abstraction for various functions+classes
+ that need to accept filenames.
+
+ This source is placed in the Public Domain, do with it what you will
+ It was originally written by Jason Gunthorpe.
+
+ ##################################################################### */
+ /*}}}*/
+// Header section: pkglib
+#ifndef PKGLIB_FILEUTL_H
+#define PKGLIB_FILEUTL_H
+
+#include <string>
+
+class File
+{
+ protected:
+ int iFd;
+
+ enum LocalFlags {AutoClose = (1<<0),Fail = (1<<1),DelOnFail = (1<<2)};
+ unsigned long Flags;
+ string FileName;
+
+ public:
+ enum OpenMode {ReadOnly,WriteEmpty,WriteExists};
+
+ bool Read(void *To,unsigned long Size);
+ bool Write(void *From,unsigned long Size);
+ bool Seek(unsigned long To);
+ unsigned long Size();
+ bool Close();
+
+ // Simple manipulators
+ inline int Fd() {return iFd;};
+ inline bool IsOpen() {return iFd >= 0;};
+ inline bool Failed() {return (Flags & Fail) == Fail;};
+ inline void EraseOnFailure() {Flags |= DelOnFail;};
+ inline void OpFail() {Flags |= Fail;};
+
+ File(string FileName,OpenMode Mode,unsigned long Perms = 0666);
+ File(int Fd) : iFd(Fd), Flags(AutoClose) {};
+ File(int Fd,bool) : iFd(Fd), Flags(0) {};
+ virtual ~File();
+};
+
+bool CopyFile(string From,string To);
+int GetLock(string File,bool Errors = true);
+bool FileExists(string File);
+string SafeGetCWD();
+
+#endif
diff --git a/apt-pkg/contrib/mmap.cc b/apt-pkg/contrib/mmap.cc
new file mode 100644
index 000000000..85cac1cca
--- /dev/null
+++ b/apt-pkg/contrib/mmap.cc
@@ -0,0 +1,227 @@
+// -*- mode: cpp; mode: fold -*-
+// Description /*{{{*/
+// $Id: mmap.cc,v 1.1 1998/07/02 02:58:13 jgg Exp $
+/* ######################################################################
+
+ MMap Class - Provides 'real' mmap or a faked mmap using read().
+
+ MMap cover class.
+
+ Some broken versions of glibc2 (libc6) have a broken definition
+ of mmap that accepts a char * -- all other systems (and libc5) use
+ void *. We can't safely do anything here that would be portable, so
+ libc6 generates warnings -- which should be errors, g++ isn't properly
+ strict.
+
+ The configure test notes that some OS's have broken private mmap's
+ so on those OS's we can't use mmap. This means we have to use
+ configure to test mmap and can't rely on the POSIX
+ _POSIX_MAPPED_FILES test.
+
+ ##################################################################### */
+ /*}}}*/
+// Include Files /*{{{*/
+#define _BSD_SOURCE
+#include <pkglib/mmap.h>
+#include <pkglib/error.h>
+
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/user.h>
+#include <unistd.h>
+#include <fcntl.h>
+ /*}}}*/
+
+// MMap::MMap - Constructor /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+MMap::MMap(File &F,unsigned long Flags) : Fd(F), Flags(Flags), iSize(0),
+ Base(0)
+{
+ if ((Flags & NoImmMap) != NoImmMap)
+ Map();
+}
+ /*}}}*/
+// MMap::~MMap - Destructor /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+MMap::~MMap()
+{
+ Close(true);
+}
+ /*}}}*/
+// MMap::Map - Perform the mapping /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool MMap::Map()
+{
+ iSize = Fd.Size();
+
+ // Set the permissions.
+ int Prot = PROT_READ;
+ int Map = MAP_SHARED;
+ if ((Flags & ReadOnly) != ReadOnly)
+ Prot |= PROT_WRITE;
+ if ((Flags & Public) != Public)
+ Map = MAP_PRIVATE;
+
+ // 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 true;
+}
+ /*}}}*/
+// MMap::Close - Close the map /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool MMap::Close(bool DoClose)
+{
+ if (Fd.IsOpen() == false)
+ return true;
+
+ Sync();
+
+ if (munmap((char *)Base,iSize) != 0)
+ _error->Warning("Unable to munmap");
+
+ iSize = 0;
+ if (DoClose == true)
+ Fd.Close();
+ return true;
+}
+ /*}}}*/
+// MMap::Sync - Syncronize the map with the disk /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool MMap::Sync()
+{
+ if ((Flags & ReadOnly) == ReadOnly)
+ if (msync((char *)Base,iSize,MS_SYNC) != 0)
+ return _error->Error("msync","Unable to write mmap");
+ return true;
+}
+ /*}}}*/
+// MMap::Sync - Syncronize a section of the file to disk /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool MMap::Sync(unsigned long Start,unsigned long Stop)
+{
+ if ((Flags & ReadOnly) == ReadOnly)
+ if (msync((char *)Base+(int)(Start/PAGE_SIZE)*PAGE_SIZE,Stop - Start,MS_SYNC) != 0)
+ return _error->Error("msync","Unable to write mmap");
+ return true;
+}
+ /*}}}*/
+
+// DynamicMMap::DynamicMMap - Constructor /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+DynamicMMap::DynamicMMap(File &F,unsigned long Flags,unsigned long WorkSpace) :
+ MMap(F,Flags | NoImmMap), WorkSpace(WorkSpace)
+{
+ unsigned long EndOfFile = Fd.Size();
+ Fd.Seek(WorkSpace);
+ char C = 0;
+ Fd.Write(&C,sizeof(C));
+ Map();
+ iSize = EndOfFile;
+}
+ /*}}}*/
+// DynamicMMap::~DynamicMMap - Destructor /*{{{*/
+// ---------------------------------------------------------------------
+/* We truncate the file to the size of the memory data set */
+DynamicMMap::~DynamicMMap()
+{
+ unsigned long EndOfFile = iSize;
+ Close(false);
+ ftruncate(Fd.Fd(),EndOfFile);
+ Fd.Close();
+}
+ /*}}}*/
+// DynamicMMap::RawAllocate - Allocate a raw chunk of unaligned space /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+unsigned long DynamicMMap::RawAllocate(unsigned long Size)
+{
+ unsigned long Result = iSize;
+ iSize += Size;
+
+ // Just in case error check
+ if (Result > WorkSpace)
+ {
+ _error->Error("Dynamic MMap ran out of room");
+ return 0;
+ }
+
+ return Result;
+}
+ /*}}}*/
+// DynamicMMap::Allocate - Pooled aligned allocation /*{{{*/
+// ---------------------------------------------------------------------
+/* This allocates an Item of size ItemSize so that it is aligned to its
+ size in the file. */
+unsigned long DynamicMMap::Allocate(unsigned long ItemSize)
+{
+ // Look for a matching pool entry
+ Pool *I;
+ Pool *Empty = 0;
+ for (I = Pools; I != Pools + PoolCount; I++)
+ {
+ if (I->ItemSize == 0)
+ Empty = I;
+ if (I->ItemSize == ItemSize)
+ break;
+ }
+
+ // No pool is allocated, use an unallocated one
+ if (I == Pools + PoolCount)
+ {
+ // Woops, we ran out, the calling code should allocate more.
+ if (Empty == 0)
+ {
+ _error->Error("Ran out of allocation pools");
+ return 0;
+ }
+
+ I = Empty;
+ I->ItemSize = ItemSize;
+ I->Count = 0;
+ }
+
+ // Out of space, allocate some more
+ if (I->Count == 0)
+ {
+ I->Count = 20*1024/ItemSize;
+ I->Start = RawAllocate(I->Count*ItemSize);
+ }
+
+ I->Count--;
+ unsigned long Result = I->Start;
+ I->Start += ItemSize;
+ return Result/ItemSize;
+}
+ /*}}}*/
+// DynamicMMap::WriteString - Write a string to the file /*{{{*/
+// ---------------------------------------------------------------------
+/* Strings are not aligned to anything */
+unsigned long DynamicMMap::WriteString(const char *String,
+ unsigned long Len)
+{
+ unsigned long Result = iSize;
+ // Just in case error check
+ if (Result > WorkSpace)
+ {
+ _error->Error("Dynamic MMap ran out of room");
+ return 0;
+ }
+
+ if (Len == 0)
+ Len = strlen(String);
+ iSize += Len + 1;
+ memcpy((char *)Base + Result,String,Len);
+ ((char *)Base)[Result + Len] = 0;
+ return Result;
+}
+ /*}}}*/
diff --git a/apt-pkg/contrib/mmap.h b/apt-pkg/contrib/mmap.h
new file mode 100644
index 000000000..096304177
--- /dev/null
+++ b/apt-pkg/contrib/mmap.h
@@ -0,0 +1,92 @@
+// -*- mode: cpp; mode: fold -*-
+// Description /*{{{*/
+// $Id: mmap.h,v 1.1 1998/07/02 02:58:13 jgg Exp $
+/* ######################################################################
+
+ MMap Class - Provides 'real' mmap or a faked mmap using read().
+
+ The purpose of this code is to provide a generic way for clients to
+ access the mmap function. In enviroments that do not support mmap
+ from file fd's this function will use read and normal allocated
+ memory.
+
+ Writing to a public mmap will always fully comit all changes when the
+ class is deleted. Ie it will rewrite the file, unless it is readonly
+
+ The DynamicMMap class is used to help the on-disk data structure
+ generators. It provides a large allocated workspace and members
+ to allocate space from the workspace in an effecient fashion.
+
+ This source is placed in the Public Domain, do with it what you will
+ It was originally written by Jason Gunthorpe.
+
+ ##################################################################### */
+ /*}}}*/
+// Header section: pkglib
+#ifndef PKGLIB_MMAP_H
+#define PKGLIB_MMAP_H
+
+#include <string>
+#include <pkglib/fileutl.h>
+
+class MMap
+{
+ protected:
+
+ File &Fd;
+ unsigned long Flags;
+ unsigned long iSize;
+ void *Base;
+
+ bool Map();
+ bool Close(bool DoClose = true);
+
+ public:
+
+ enum OpenFlags {NoImmMap = (1<<0),Public = (1<<1),ReadOnly = (1<<2)};
+
+ // Simple accessors
+ inline operator void *() {return Base;};
+ inline void *Data() {return Base;};
+ inline unsigned long Size() {return iSize;};
+
+ // File manipulators
+ bool Sync();
+ bool Sync(unsigned long Start,unsigned long Stop);
+
+ MMap(File &F,unsigned long Flags);
+ virtual ~MMap();
+};
+
+class DynamicMMap : public MMap
+{
+ public:
+
+ // This is the allocation pool structure
+ struct Pool
+ {
+ unsigned long ItemSize;
+ unsigned long Start;
+ unsigned long Count;
+ };
+
+ protected:
+
+ unsigned long WorkSpace;
+ Pool *Pools;
+ unsigned int PoolCount;
+
+ public:
+
+ // Allocation
+ unsigned long RawAllocate(unsigned long Size);
+ unsigned long Allocate(unsigned long ItemSize);
+ unsigned long WriteString(const char *String,unsigned long Len = 0);
+ inline unsigned long WriteString(string S) {return WriteString(S.begin(),S.size());};
+ void UsePools(Pool &P,unsigned int Count) {Pools = &P; PoolCount = Count;};
+
+ DynamicMMap(File &F,unsigned long Flags,unsigned long WorkSpace = 1024*1024);
+ virtual ~DynamicMMap();
+};
+
+#endif
diff --git a/apt-pkg/contrib/system.h b/apt-pkg/contrib/system.h
new file mode 100644
index 000000000..e652348b0
--- /dev/null
+++ b/apt-pkg/contrib/system.h
@@ -0,0 +1,57 @@
+// -*- mode: cpp; mode: fold -*-
+// Description /*{{{*/
+// $Id: system.h,v 1.1 1998/07/02 02:58:13 jgg Exp $
+/* ######################################################################
+
+ System Header - Usefull private definitions
+
+ This source is placed in the Public Domain, do with it what you will
+ It was originally written by Brian C. White.
+
+ ##################################################################### */
+ /*}}}*/
+// Private header
+// Header section: /
+#ifndef SYSTEM_H
+#define SYSTEM_H
+
+// MIN_VAL(SINT16) will return -0x8000 and MAX_VAL(SINT16) = 0x7FFF
+#define MIN_VAL(t) (((t)(-1) > 0) ? (t)( 0) : (t)(((1L<<(sizeof(t)*8-1)) )))
+#define MAX_VAL(t) (((t)(-1) > 0) ? (t)(-1) : (t)(((1L<<(sizeof(t)*8-1))-1)))
+
+// Min/Max functions
+#if defined(__HIGHC__)
+#define MIN(x,y) _min(x,y)
+#define MAX(x,y) _max(x,y)
+#endif
+
+// GNU C++ has a min/max operator <coolio>
+#if defined(__GNUG__)
+#define MIN(A,B) ((A) <? (B))
+#define MAX(A,B) ((A) >? (B))
+#endif
+
+/* Templates tend to mess up existing code that uses min/max because of the
+ strict matching requirements */
+#if !defined(MIN)
+#define MIN(A,B) ((A) < (B)?(A):(B))
+#define MAX(A,B) ((A) > (B)?(A):(B))
+#endif
+
+/* Bound functions, bound will return the value b within the limits a-c
+ bounv will change b so that it is within the limits of a-c. */
+#define _bound(a,b,c) MIN(c,MAX(b,a))
+#define _boundv(a,b,c) b = _bound(a,b,c)
+#define ABS(a) (((a) < (0)) ?-(a) : (a))
+
+/* Usefull count macro, use on an array of things and it will return the
+ number of items in the array */
+#define _count(a) (sizeof(a)/sizeof(a[0]))
+
+// Flag Macros
+#define FLAG(f) (1L << (f))
+#define SETFLAG(v,f) ((v) |= FLAG(f))
+#define CLRFLAG(v,f) ((v) &=~FLAG(f))
+#define CHKFLAG(v,f) ((v) & FLAG(f) ? true : false)
+
+#endif
diff --git a/apt-pkg/pkgcache.cc b/apt-pkg/pkgcache.cc
new file mode 100644
index 000000000..b75fe6d94
--- /dev/null
+++ b/apt-pkg/pkgcache.cc
@@ -0,0 +1,360 @@
+// -*- mode: cpp; mode: fold -*-
+// Description /*{{{*/
+// $Id: pkgcache.cc,v 1.1 1998/07/02 02:58:12 jgg Exp $
+/* ######################################################################
+
+ Package Cache - Accessor code for the cache
+
+ Please see doc/pkglib/cache.sgml for a more detailed description of
+ this format. Also be sure to keep that file up-to-date!!
+
+ This is the general utility functions for cache managment. They provide
+ a complete set of accessor functions for the cache. The cacheiterators
+ header contains the STL-like iterators that can be used to easially
+ navigate the cache as well as seemlessly dereference the mmap'd
+ indexes. Use these always.
+
+ The main class provides for ways to get package indexes and some
+ general lookup functions to start the iterators.
+
+ ##################################################################### */
+ /*}}}*/
+// Include Files /*{{{*/
+#include <pkglib/pkgcache.h>
+#include <pkglib/version.h>
+#include <pkglib/error.h>
+#include <system.h>
+
+#include <string>
+#include <sys/stat.h>
+#include <unistd.h>
+ /*}}}*/
+
+// Cache::Header::Header - Constructor /*{{{*/
+// ---------------------------------------------------------------------
+/* Simply initialize the header */
+pkgCache::Header::Header()
+{
+ Signature = 0x98FE76DC;
+
+ /* Whenever the structures change the major version should be bumped,
+ whenever the generator changes the minor version should be bumped. */
+ MajorVersion = 2;
+ MinorVersion = 0;
+ Dirty = true;
+
+ HeaderSz = sizeof(pkgCache::Header);
+ PackageSz = sizeof(pkgCache::Package);
+ PackageFileSz = sizeof(pkgCache::PackageFile);
+ VersionSz = sizeof(pkgCache::Version);
+ DependencySz = sizeof(pkgCache::Dependency);
+ ProvidesSz = sizeof(pkgCache::Provides);
+
+ PackageCount = 0;
+ VersionCount = 0;
+ DependsCount = 0;
+ PackageFileCount = 0;
+
+ FileList = 0;
+ StringList = 0;
+ memset(HashTable,0,sizeof(HashTable));
+ memset(Pools,0,sizeof(Pools));
+}
+ /*}}}*/
+// Cache::Header::CheckSizes - Check if the two headers have same *sz /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool pkgCache::Header::CheckSizes(Header &Against) const
+{
+ if (HeaderSz == Against.HeaderSz &&
+ PackageSz == Against.PackageSz &&
+ PackageFileSz == Against.PackageFileSz &&
+ VersionSz == Against.VersionSz &&
+ DependencySz == Against.DependencySz &&
+ ProvidesSz == Against.ProvidesSz)
+ return true;
+ return false;
+}
+ /*}}}*/
+
+// Cache::pkgCache - Constructor /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+pkgCache::pkgCache(MMap &Map) : Map(Map)
+{
+ ReMap();
+}
+ /*}}}*/
+// Cache::ReMap - Reopen the cache file /*{{{*/
+// ---------------------------------------------------------------------
+/* If the file is already closed then this will open it open it. */
+bool pkgCache::ReMap()
+{
+ // Apply the typecasts.
+ HeaderP = (Header *)Map.Data();
+ PkgP = (Package *)Map.Data();
+ PkgFileP = (PackageFile *)Map.Data();
+ VerP = (Version *)Map.Data();
+ ProvideP = (Provides *)Map.Data();
+ DepP = (Dependency *)Map.Data();
+ StringItemP = (StringItem *)Map.Data();
+ StrP = (char *)Map.Data();
+
+ cout << "Size is " << Map.Size() << endl;
+ if (Map.Size() == 0)
+ return false;
+
+ // Check the header
+ Header DefHeader;
+ if (HeaderP->Signature != DefHeader.Signature ||
+ HeaderP->Dirty == true)
+ 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 true;
+}
+ /*}}}*/
+// Cache::Hash - Hash a string /*{{{*/
+// ---------------------------------------------------------------------
+/* This is used to generate the hash entries for the HashTable. With my
+ package list from bo this function gets 94% table usage on a 512 item
+ table (480 used items) */
+unsigned long pkgCache::sHash(string Str)
+{
+ unsigned long Hash = 0;
+ for (const char *I = Str.begin(); I != Str.end(); I++)
+ Hash += *I * ((Str.end() - I + 1));
+ Header H;
+ return Hash % _count(H.HashTable);
+}
+
+unsigned long pkgCache::sHash(const char *Str)
+{
+ unsigned long Hash = 0;
+ const char *End = Str + strlen(Str);
+ for (const char *I = Str; I != End; I++)
+ Hash += *I * ((End - I + 1));
+ Header H;
+ return Hash % _count(H.HashTable);
+}
+
+ /*}}}*/
+// Cache::FindPkg - Locate a package by name /*{{{*/
+// ---------------------------------------------------------------------
+/* Returns 0 on error, pointer to the package otherwise */
+pkgCache::PkgIterator pkgCache::FindPkg(string Name)
+{
+ // Look at the hash bucket
+ Package *Pkg = PkgP + HeaderP->HashTable[Hash(Name)];
+ for (; Pkg != PkgP; Pkg = PkgP + Pkg->NextPackage)
+ {
+ if (Pkg->Name != 0 && StrP + Pkg->Name == Name)
+ return PkgIterator(*this,Pkg);
+ }
+ return PkgIterator(*this,0);
+}
+ /*}}}*/
+
+// Cache::PkgIterator - operator ++ - Postfix incr /*{{{*/
+// ---------------------------------------------------------------------
+/* This will advance to the next logical package in the hash table. */
+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))
+ {
+ HashIndex++;
+ Pkg = Owner->PkgP + Owner->HeaderP->HashTable[HashIndex];
+ }
+};
+ /*}}}*/
+// Bases for iterator classes /*{{{*/
+void pkgCache::VerIterator::_dummy() {}
+void pkgCache::DepIterator::_dummy() {}
+void pkgCache::PrvIterator::_dummy() {}
+ /*}}}*/
+// PkgIterator::State - Check the State of the package /*{{{*/
+// ---------------------------------------------------------------------
+/* By this we mean if it is either cleanly installed or cleanly removed. */
+pkgCache::PkgIterator::OkState pkgCache::PkgIterator::State() const
+{
+ if (Pkg->CurrentState == pkgSTATE_UnPacked ||
+ Pkg->CurrentState == pkgSTATE_HalfConfigured)
+ return NeedsConfigure;
+
+ if (Pkg->CurrentState == pkgSTATE_UnInstalled ||
+ Pkg->CurrentState == pkgSTATE_HalfInstalled ||
+ Pkg->InstState != pkgSTATE_Ok)
+ return NeedsUnpack;
+
+ return NeedsNothing;
+}
+ /*}}}*/
+// DepIterator::IsCritical - Returns true if the dep is important /*{{{*/
+// ---------------------------------------------------------------------
+/* Currently critical deps are defined as depends, predepends and
+ conflicts. */
+bool pkgCache::DepIterator::IsCritical()
+{
+ if (Dep->Type == pkgDEP_Conflicts || Dep->Type == pkgDEP_Depends ||
+ Dep->Type == pkgDEP_PreDepends)
+ return true;
+ return false;
+}
+ /*}}}*/
+// DepIterator::SmartTargetPkg - Resolve dep target pointers w/provides /*{{{*/
+// ---------------------------------------------------------------------
+/* This intellegently looks at dep target packages and tries to figure
+ out which package should be used. This is needed to nicely handle
+ provide mapping. If the target package has no other providing packages
+ 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 */
+bool pkgCache::DepIterator::SmartTargetPkg(PkgIterator &Result)
+{
+ Result = TargetPkg();
+
+ // No provides at all
+ if (Result->ProvidesList == 0)
+ return false;
+
+ // There is the Base package and the providing ones which is at least 2
+ if (Result->VersionList != 0)
+ return true;
+
+ /* We have to skip over indirect provisions of the package that
+ owns the dependency. For instance, if libc5-dev depends on the
+ virtual package libc-dev which is provided by libc5-dev and libc6-dev
+ we must ignore libc5-dev when considering the provides list. */
+ PrvIterator PStart = Result.ProvidesList();
+ for (; PStart.end() != true && PStart.OwnerPkg() == ParentPkg(); PStart++);
+
+ // Nothing but indirect self provides
+ if (PStart.end() == true)
+ return false;
+
+ // Check for single packages in the provides list
+ PrvIterator P = PStart;
+ for (; P.end() != true; P++)
+ {
+ // Skip over self provides
+ if (P.OwnerPkg() == ParentPkg())
+ continue;
+ if (PStart.OwnerPkg() != P.OwnerPkg())
+ break;
+ }
+
+ // 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
+ provides. It includes every possible package-version that could satisfy
+ the dependency. The last item in the list has a 0. */
+pkgCache::Version **pkgCache::DepIterator::AllTargets()
+{
+ Version **Res = 0;
+ unsigned long Size =0;
+ while (1)
+ {
+ Version **End = Res;
+ PkgIterator DPkg = TargetPkg();
+
+ // Walk along the actual package providing versions
+ for (VerIterator I = DPkg.VersionList(); I.end() == false; I++)
+ {
+ if (pkgCheckDep(TargetVer(),I.VerStr(),Dep->CompareOp) == false)
+ continue;
+
+ if (Dep->Type == pkgDEP_Conflicts && ParentPkg() == I.ParentPkg())
+ continue;
+
+ Size++;
+ if (Res != 0)
+ *End++ = I;
+ }
+
+ // Follow all provides
+ for (PrvIterator I = DPkg.ProvidesList(); I.end() == false; I++)
+ {
+ if (pkgCheckDep(TargetVer(),I.ProvideVersion(),Dep->CompareOp) == false)
+ continue;
+
+ if (Dep->Type == pkgDEP_Conflicts && ParentPkg() == I.OwnerPkg())
+ continue;
+
+ Size++;
+ if (Res != 0)
+ *End++ = I.OwnerVer();
+ }
+
+ // Do it again and write it into the array
+ if (Res == 0)
+ {
+ Res = new Version *[Size+1];
+ Size = 0;
+ }
+ else
+ {
+ *End = 0;
+ break;
+ }
+ }
+
+ return Res;
+}
+ /*}}}*/
+// VerIterator::CompareVer - Fast version compare for same pkgs /*{{{*/
+// ---------------------------------------------------------------------
+/* This just looks over the version list to see if B is listed before A. In
+ most cases this will return in under 4 checks, ver lists are short. */
+int pkgCache::VerIterator::CompareVer(const VerIterator &B) const
+{
+ // Check if they are equal
+ if (*this == B)
+ return 0;
+ if (end() == true)
+ return -1;
+ if (B.end() == true)
+ return 1;
+
+ /* Start at A and look for B. If B is found then A > B otherwise
+ B was before A so A < B */
+ VerIterator I = *this;
+ for (;I.end() == false; I++)
+ if (I == B)
+ return 1;
+ return -1;
+}
+ /*}}}*/
+// 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
+ stored during generation. Date checks should probably also be
+ included here. */
+bool pkgCache::PkgFileIterator::IsOk()
+{
+ struct stat Buf;
+ if (stat(FileName(),&Buf) != 0)
+ return false;
+
+ if (Buf.st_size != (signed)File->Size || Buf.st_mtime != File->mtime)
+ return false;
+
+ return true;
+}
+ /*}}}*/
diff --git a/apt-pkg/pkgcache.h b/apt-pkg/pkgcache.h
new file mode 100644
index 000000000..0dc939a51
--- /dev/null
+++ b/apt-pkg/pkgcache.h
@@ -0,0 +1,280 @@
+// -*- mode: cpp; mode: fold -*-
+// Description /*{{{*/
+// $Id: pkgcache.h,v 1.1 1998/07/02 02:58:12 jgg Exp $
+/* ######################################################################
+
+ Cache - Structure definitions for the cache file
+
+ Please see doc/pkglib/cache.sgml for a more detailed description of
+ this format. Also be sure to keep that file up-to-date!!
+
+ Clients should always use the CacheIterators classes for access to the
+ cache. They provide a simple STL-like method for traversing the links
+ of the datastructure.
+
+ See pkgcachegen.h for information about generating cache structures.
+
+ ##################################################################### */
+ /*}}}*/
+// Header section: pkglib
+#ifndef PKGLIB_PKGCACHE_H
+#define PKGLIB_PKGCACHE_H
+
+#include <string>
+#include <time.h>
+#include <pkglib/mmap.h>
+
+// Definitions for Depends::Type
+#define pkgDEP_Depends 1
+#define pkgDEP_PreDepends 2
+#define pkgDEP_Suggests 3
+#define pkgDEP_Recommends 4
+#define pkgDEP_Conflicts 5
+#define pkgDEP_Replaces 6
+
+// Definitions for Version::Priority
+#define pkgPRIO_Important 1
+#define pkgPRIO_Required 2
+#define pkgPRIO_Standard 3
+#define pkgPRIO_Optional 4
+#define pkgPRIO_Extra 5
+
+// Definitions for Package::SelectedState
+#define pkgSTATE_Unkown 0
+#define pkgSTATE_Install 1
+#define pkgSTATE_Hold 2
+#define pkgSTATE_DeInstall 3
+#define pkgSTATE_Purge 4
+
+// Definitions for Package::Flags
+#define pkgFLAG_Auto (1 << 0)
+#define pkgFLAG_New (1 << 1)
+#define pkgFLAG_Obsolete (1 << 2)
+#define pkgFLAG_Essential (1 << 3)
+#define pkgFLAG_ImmediateConf (1 << 4)
+
+// Definitions for Package::InstState
+#define pkgSTATE_Ok 0
+#define pkgSTATE_ReInstReq 1
+#define pkgSTATE_Hold 2
+#define pkgSTATE_HoldReInstReq 3
+
+// Definitions for Package::CurrentState
+#define pkgSTATE_NotInstalled 0
+#define pkgSTATE_UnPacked 1
+#define pkgSTATE_HalfConfigured 2
+#define pkgSTATE_UnInstalled 3
+#define pkgSTATE_HalfInstalled 4
+#define pkgSTATE_ConfigFiles 5
+#define pkgSTATE_Installed 6
+
+// Definitions for PackageFile::Flags
+#define pkgFLAG_NotSource (1 << 0)
+
+// Definitions for Dependency::CompareOp
+#define pkgOP_OR 0x10
+#define pkgOP_LESSEQ 0x1
+#define pkgOP_GREATEREQ 0x2
+#define pkgOP_LESS 0x3
+#define pkgOP_GREATER 0x4
+#define pkgOP_EQUALS 0x5
+#define pkgOP_NOTEQUALS 0x6
+
+class pkgCache
+{
+ public:
+ // Cache element predeclarations
+ struct Header;
+ struct Package;
+ struct PackageFile;
+ struct Version;
+ struct Provides;
+ struct Dependency;
+ struct StringItem;
+
+ // Iterators
+ class PkgIterator;
+ class VerIterator;
+ class DepIterator;
+ class PrvIterator;
+ class PkgFileIterator;
+ friend PkgIterator;
+ friend VerIterator;
+ friend DepIterator;
+ friend PrvIterator;
+ friend PkgFileIterator;
+
+ protected:
+
+ // Memory mapped cache file
+ string CacheFile;
+ MMap &Map;
+
+ bool Public;
+ bool ReadOnly;
+
+ static unsigned long sHash(string S);
+ static unsigned long sHash(const char *S);
+
+ public:
+
+ // Pointers to the arrays of items
+ Header *HeaderP;
+ Package *PkgP;
+ PackageFile *PkgFileP;
+ Version *VerP;
+ Provides *ProvideP;
+ Dependency *DepP;
+ StringItem *StringItemP;
+ char *StrP;
+
+ virtual bool ReMap();
+ inline bool Sync() {return Map.Sync();};
+
+ // 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);};
+
+ // Accessors
+ PkgIterator FindPkg(string Name);
+ Header &Head() {return *HeaderP;};
+ inline PkgIterator PkgBegin();
+ inline PkgIterator PkgEnd();
+
+ pkgCache(MMap &Map);
+ virtual ~pkgCache() {};
+};
+
+// Header structure
+struct pkgCache::Header
+{
+ // Signature information
+ unsigned long Signature;
+ short MajorVersion;
+ short MinorVersion;
+ bool Dirty;
+
+ // Size of structure values
+ unsigned short HeaderSz;
+ unsigned short PackageSz;
+ unsigned short PackageFileSz;
+ unsigned short VersionSz;
+ unsigned short DependencySz;
+ unsigned short ProvidesSz;
+
+ // Structure counts
+ unsigned long PackageCount;
+ unsigned long VersionCount;
+ unsigned long DependsCount;
+ unsigned long PackageFileCount;
+
+ // Offsets
+ unsigned long FileList; // struct PackageFile
+ unsigned long StringList; // struct StringItem
+
+ /* Allocation pools, there should be one of these for each structure
+ excluding the header */
+ DynamicMMap::Pool Pools[6];
+
+ // Rapid package name lookup
+ unsigned long HashTable[512];
+
+ bool CheckSizes(Header &Against) const;
+ Header();
+};
+
+struct pkgCache::Package
+{
+ // Pointers
+ unsigned long Name; // Stringtable
+ unsigned long VersionList; // Version
+ unsigned long TargetVer; // Version
+ unsigned long CurrentVer; // Version
+ unsigned long TargetDist; // StringTable (StringItem)
+ unsigned long Section; // StringTable (StringItem)
+
+ // Linked list
+ unsigned long NextPackage; // Package
+ unsigned long RevDepends; // Dependency
+ unsigned long ProvidesList; // Provides
+
+ // Install/Remove/Purge etc
+ unsigned char SelectedState; // What
+ unsigned char InstState; // Flags
+ unsigned char CurrentState; // State
+
+ unsigned short ID;
+ unsigned short Flags;
+};
+
+struct pkgCache::PackageFile
+{
+ // Names
+ unsigned long FileName; // Stringtable
+ unsigned long Version; // Stringtable
+ unsigned long Distribution; // Stringtable
+ unsigned long Size;
+
+ // Linked list
+ unsigned long NextFile; // PackageFile
+ unsigned short ID;
+ unsigned short Flags;
+ time_t mtime; // Modification time for the file
+};
+
+struct pkgCache::Version
+{
+ unsigned long VerStr; // Stringtable
+ unsigned long File; // PackageFile
+ unsigned long Section; // StringTable (StringItem)
+
+ // Lists
+ unsigned long NextVer; // Version
+ unsigned long DependsList; // Dependency
+ unsigned long ParentPkg; // Package
+ unsigned long ProvidesList; // Provides
+
+ unsigned long Offset;
+ unsigned long Size;
+ unsigned long InstalledSize;
+ unsigned short ID;
+ unsigned char Priority;
+};
+
+struct pkgCache::Dependency
+{
+ unsigned long Version; // Stringtable
+ unsigned long Package; // Package
+ unsigned long NextDepends; // Dependency
+ unsigned long NextRevDepends; // Dependency
+ unsigned long ParentVer; // Version
+
+ // Specific types of depends
+ unsigned char Type;
+ unsigned char CompareOp;
+ unsigned short ID;
+};
+
+struct pkgCache::Provides
+{
+ unsigned long ParentPkg; // Pacakge
+ unsigned long Version; // Version
+ unsigned long ProvideVersion; // Stringtable
+ unsigned long NextProvides; // Provides
+ unsigned long NextPkgProv; // Provides
+};
+
+struct pkgCache::StringItem
+{
+ unsigned long String; // Stringtable
+ unsigned long NextItem; // StringItem
+};
+
+#include <pkglib/cacheiterators.h>
+
+inline pkgCache::PkgIterator pkgCache::PkgBegin()
+ {return PkgIterator(*this);};
+inline pkgCache::PkgIterator pkgCache::PkgEnd()
+ {return PkgIterator(*this,PkgP);};
+
+#endif
diff --git a/apt-pkg/pkgcachegen.cc b/apt-pkg/pkgcachegen.cc
new file mode 100644
index 000000000..cb0fd3f74
--- /dev/null
+++ b/apt-pkg/pkgcachegen.cc
@@ -0,0 +1,184 @@
+// -*- mode: cpp; mode: fold -*-
+// Description /*{{{*/
+// $Id: pkgcachegen.cc,v 1.1 1998/07/02 02:58:12 jgg Exp $
+/* ######################################################################
+
+ Package Cache Generator - Generator for the cache structure.
+
+ This builds the cache structure from the abstract package list parser.
+
+ ##################################################################### */
+ /*}}}*/
+// Include Files /*{{{*/
+#include <pkglib/pkgcachegen.h>
+#include <pkglib/error.h>
+#include <pkglib/version.h>
+
+#include <sys/stat.h>
+#include <unistd.h>
+ /*}}}*/
+
+// CacheGenerator::pkgCacheGenerator - Constructor /*{{{*/
+// ---------------------------------------------------------------------
+/* We set the diry flag and make sure that is written to the disk */
+pkgCacheGenerator::pkgCacheGenerator(DynamicMMap &Map) : Map(Map), Cache(Map)
+{
+ if (_error->PendingError() == true)
+ return;
+
+ if (Map.Size() == 0)
+ {
+ Map.RawAllocate(sizeof(pkgCache::Header));
+ *Cache.HeaderP = pkgCache::Header();
+ }
+ Cache.HeaderP->Dirty = true;
+ Map.Sync(0,sizeof(pkgCache::Header));
+ Map.UsePools(*Cache.HeaderP->Pools,sizeof(Cache.HeaderP->Pools)/sizeof(Cache.HeaderP->Pools[0]));
+}
+ /*}}}*/
+// CacheGenerator::~pkgCacheGenerator - Destructor /*{{{*/
+// ---------------------------------------------------------------------
+/* We sync the data then unset the dirty flag in two steps so as to
+ advoid a problem during a crash */
+pkgCacheGenerator::~pkgCacheGenerator()
+{
+ if (_error->PendingError() == true)
+ return;
+ if (Map.Sync() == false)
+ return;
+
+ Cache.HeaderP->Dirty = false;
+ Map.Sync(0,sizeof(pkgCache::Header));
+}
+ /*}}}*/
+// CacheGenerator::MergeList - Merge the package list /*{{{*/
+// ---------------------------------------------------------------------
+/* This provides the generation of the entries in the cache. Each loop
+ goes through a single package record from the underlying parse engine. */
+bool pkgCacheGenerator::MergeList(ListParser &List)
+{
+ List.Owner = this;
+
+ do
+ {
+ // Get a pointer to the package structure
+ string Package = List.Package();
+ pkgCache::PkgIterator Pkg = Cache.FindPkg(Package);
+ if (Pkg.end() == false)
+ {
+ if (NewPackage(Pkg,Package) == false)
+ return false;
+
+ if (List.NewPackage(Pkg) == false)
+ return false;
+ }
+ if (List.UsePackage(Pkg) == false)
+ return false;
+
+ /* Get a pointer to the version structure. We know the list is sorted
+ so we use that fact in the search. Insertion of new versions is
+ done with correct sorting */
+ string Version = List.Version();
+ pkgCache::VerIterator Ver = Pkg.VersionList();
+ unsigned long *Last = &Pkg->VersionList;
+ int Res;
+ for (; Ver.end() == false; Ver++, Last = &Ver->NextVer)
+ {
+ Res = pkgVersionCompare(Version.begin(),Version.end(),Ver.VerStr(),
+ Ver.VerStr() + strlen(Ver.VerStr()));
+ if (Res >= 0)
+ break;
+ }
+
+ /* We already have a version for this item, record that we
+ saw it */
+ if (Res == 0)
+ {
+ if (NewFileVer(Ver,List) == false)
+ return false;
+
+ continue;
+ }
+
+ // Add a new version
+ *Last = NewVersion(Ver,*Last);
+ if (List.NewVersion(Ver) == false)
+ return false;
+
+ if (NewFileVer(Ver,List) == false)
+ return false;
+ }
+ while (List.Step() == true);
+
+ return true;
+}
+ /*}}}*/
+// CacheGenerator::NewPackage - Add a new package /*{{{*/
+// ---------------------------------------------------------------------
+/* This creates a new package structure and adds it to the hash table */
+bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator Pkg,string Name)
+{
+ // Get a structure
+ unsigned long Package = Map.Allocate(sizeof(pkgCache::Package));
+ if (Package == 0)
+ return false;
+
+ Pkg = pkgCache::PkgIterator(Cache,Cache.PackageP + Package);
+
+ // Insert it into the hash table
+ unsigned long Hash = Map.Hash(Name);
+ Pkg->NextPackage = Cache.HeaderP->HashTable[Hash];
+ Cache.HeaderP->HashTable[Hash] = Package;
+
+ // Set the name and the ID
+ Pkg->Name = Map.WriteString(Name);
+ if (Pkg->Name == 0)
+ return false;
+ Pkg->ID = Cache.HeaderP->PackageCount++;
+
+ return true;
+}
+ /*}}}*/
+// CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator Ver,
+ ListParser &List)
+{
+}
+ /*}}}*/
+// CacheGenerator::NewVersion - Create a new Version /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+unsigned long pkgCacheGenerator::NewVersion(pkgCache::VerIterator &Ver,
+ unsigned long Next)
+{
+}
+ /*}}}*/
+// 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)
+{
+ 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)
+ return false;
+
+ // Fill it in
+ CurrentFile->FileName = Map.WriteString(File);
+ CurrentFile->Size = Buf.st_size;
+ CurrentFile->mtime = Buf.st_mtime;
+ CurrentFile->NextFile = Cache.HeaderP->FileList;
+ CurrentFile->Flags = Flags;
+ PkgFileName = File;
+
+ if (CurrentFile->FileName == 0)
+ return false;
+}
+ /*}}}*/
diff --git a/apt-pkg/pkgcachegen.h b/apt-pkg/pkgcachegen.h
new file mode 100644
index 000000000..1385ab964
--- /dev/null
+++ b/apt-pkg/pkgcachegen.h
@@ -0,0 +1,69 @@
+// -*- mode: cpp; mode: fold -*-
+// Description /*{{{*/
+// $Id: pkgcachegen.h,v 1.1 1998/07/02 02:58:13 jgg Exp $
+/* ######################################################################
+
+ Package Cache Generator - Generator for the cache structure.
+
+ This builds the cache structure from the abstract package list parser.
+
+ ##################################################################### */
+ /*}}}*/
+// Header section: pkglib
+#ifndef PKGLIB_PKGCACHEGEN_H
+#define PKGLIB_PKGCACHEGEN_H
+
+#include <pkglib/pkgcache.h>
+
+class pkgCacheGenerator
+{
+ public:
+
+ class ListParser;
+
+ protected:
+
+ DynamicMMap &Map;
+ pkgCache Cache;
+
+ string PkgFileName;
+ pkgCache::PackageFile *CurrentFile;
+
+ bool NewPackage(pkgCache::PkgIterator Pkg,string Pkg);
+ bool NewFileVer(pkgCache::VerIterator Ver,ListParser &List);
+ unsigned long NewVersion(pkgCache::VerIterator &Ver,unsigned long Next);
+
+ public:
+
+ // This is the abstract package list parser class.
+ class ListParser
+ {
+ pkgCacheGenerator *Owner;
+ friend pkgCacheGenerator;
+
+ protected:
+
+ inline unsigned long WriteString(string S) {return Owner->Map.WriteString(S);};
+ inline unsigned long WriteString(const char *S,unsigned int Size) {return Owner->Map.WriteString(S,Size);};
+
+ public:
+
+ // These all operate against the current section
+ virtual string Package() = 0;
+ virtual string Version() = 0;
+ virtual bool NewVersion(pkgCache::VerIterator Ver) = 0;
+ virtual bool NewPackage(pkgCache::PkgIterator Pkg) = 0;
+ virtual bool UsePackage(pkgCache::PkgIterator Pkg) = 0;
+
+ virtual bool Step() = 0;
+ };
+ friend ListParser;
+
+ bool SelectFile(string File,unsigned long Flags = 0);
+ bool MergeList(ListParser &List);
+
+ pkgCacheGenerator(DynamicMMap &Map);
+ ~pkgCacheGenerator();
+};
+
+#endif
diff --git a/apt-pkg/tagfile.cc b/apt-pkg/tagfile.cc
new file mode 100644
index 000000000..106b0febe
--- /dev/null
+++ b/apt-pkg/tagfile.cc
@@ -0,0 +1,195 @@
+// -*- mode: cpp; mode: fold -*-
+// Description /*{{{*/
+// $Id: tagfile.cc,v 1.1 1998/07/02 02:58:13 jgg Exp $
+/* ######################################################################
+
+ Fast scanner for RFC-822 type header information
+
+ This uses a rotating 64K buffer to load the package information into.
+ The scanner runs over it and isolates and indexes a single section.
+
+ ##################################################################### */
+ /*}}}*/
+// Include Files /*{{{*/
+#include <pkglib/tagfile.h>
+#include <pkglib/error.h>
+
+#include <string>
+#include <stdio.h>
+ /*}}}*/
+
+// TagFile::pkgTagFile - Constructor /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+pkgTagFile::pkgTagFile(File &Fd) : Fd(Fd)
+{
+ Buffer = new char[64*1024];
+ Start = End = Buffer + 64*1024;
+ Left = Fd.Size();
+ Fill();
+}
+ /*}}}*/
+// TagFile::Step - Advance to the next section /*{{{*/
+// ---------------------------------------------------------------------
+/* If the Section Scanner fails we refill the buffer and try again. */
+bool pkgTagFile::Step(pkgTagSection &Tag)
+{
+ if (Tag.Scan(Start,End - Start) == false)
+ {
+ if (Fill() == false)
+ return false;
+
+ if (Tag.Scan(Start,End - Start) == false)
+ return _error->Error("Unable to parse package file");
+ }
+ Start += Tag.Length();
+ return true;
+}
+ /*}}}*/
+// TagFile::Fill - Top up the buffer /*{{{*/
+// ---------------------------------------------------------------------
+/* This takes the bit at the end of the buffer and puts it at the start
+ then fills the rest from the file */
+bool pkgTagFile::Fill()
+{
+ unsigned long Size = End - Start;
+
+ if (Left == 0)
+ {
+ if (Size <= 1)
+ return false;
+ return true;
+ }
+
+ memmove(Buffer,Start,Size);
+ Start = Buffer;
+
+ // See if only a bit of the file is left or if
+ if (Left < End - Buffer - Size)
+ {
+ if (Fd.Read(Buffer + Size,Left) == false)
+ return false;
+ End = Buffer + Size + Left;
+ Left = 0;
+ }
+ else
+ {
+ if (Fd.Read(Buffer + Size, End - Buffer - Size) == false)
+ return false;
+ Left -= End - Buffer - Size;
+ }
+ return true;
+}
+ /*}}}*/
+// TagSection::Scan - Scan for the end of the header information /*{{{*/
+// ---------------------------------------------------------------------
+/* This looks for the first double new line in the data stream. It also
+ indexes the tags in the section. */
+bool pkgTagSection::Scan(const char *Start,unsigned long MaxLength)
+{
+ const char *End = Start + MaxLength;
+ Stop = Section = Start;
+
+ TagCount = 0;
+ Indexes[TagCount++] = Stop - Section;
+ Stop++;
+ for (; Stop < End; Stop++)
+ {
+ if (Stop[-1] != '\n')
+ continue;
+ if (Stop[0] == '\n')
+ {
+ // Extra one at the end to simplify find
+ Indexes[TagCount] = Stop - Section;
+ for (; Stop[0] == '\n' && Stop < End; Stop++);
+ return true;
+ break;
+ }
+
+ if (isspace(Stop[0]) == 0)
+ Indexes[TagCount++] = Stop - Section;
+
+ // Just in case.
+ if (TagCount > sizeof(Indexes)/sizeof(Indexes[0]))
+ TagCount = sizeof(Indexes)/sizeof(Indexes[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)
+{
+ unsigned int Length = strlen(Tag);
+ for (unsigned int I = 0; I != TagCount; I++)
+ {
+ if (strncasecmp(Tag,Section + Indexes[I],Length) != 0)
+ continue;
+
+ // Make sure the colon is in the right place
+ const char *C = Section + Length + Indexes[I];
+ for (; isspace(*C) != 0; C++);
+ if (*C != ':')
+ continue;
+
+ // Strip off the gunk from the start end
+ Start = C;
+ End = Section + Indexes[I+1];
+ for (; (isspace(*Start) != 0 || *Start == ':') && Start < End; Start++);
+ for (; isspace(End[-1]) != 0 && End > Start; End--);
+ return true;
+ }
+ Start = End = 0;
+ return false;
+}
+ /*}}}*/
+
+#include <pkglib/pkgcachegen.h>
+
+int main(int argc,char *argv[])
+{
+ {
+ File F(argv[1],File::ReadOnly);
+ pkgTagFile Test(F);
+ File CacheF("./cache",File::WriteEmpty);
+ DynamicMMap Map(CacheF,MMap::Public);
+ pkgCacheGenerator Gen(Map);
+ Gen.SelectFile("tet");
+ }
+
+#if 0
+ pkgTagSection I;
+ while (Test.Step(I) == true)
+ {
+ const char *Start;
+ const char *End;
+ if (I.Find("Package",Start,End) == false)
+ {
+ cout << "Failed" << endl;
+ continue;
+ }
+
+ cout << "Package: " << string(Start,End - Start) << endl;
+
+/* for (const char *I = Start; I < End; I++)
+ {
+ const char *Begin = I;
+ bool Number = true;
+ while (isspace(*I) == 0 && ispunct(*I) == 0 && I < End)
+ {
+ if (isalpha(*I) != 0)
+ Number = false;
+ I++;
+ }
+ if (Number == false)
+ cout << string(Begin,I-Begin) << endl;
+ while ((isspace(*I) != 0 || ispunct(*I) != 0) && I < End)
+ I++;
+ I--;
+ } */
+ }
+#endif
+ _error->DumpErrors();
+}
diff --git a/apt-pkg/tagfile.h b/apt-pkg/tagfile.h
new file mode 100644
index 000000000..a7a82dd1c
--- /dev/null
+++ b/apt-pkg/tagfile.h
@@ -0,0 +1,64 @@
+// -*- mode: cpp; mode: fold -*-
+// Description /*{{{*/
+// $Id: tagfile.h,v 1.1 1998/07/02 02:58:13 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.
+
+ The parser reads the and provides methods to step linearly
+ over it or to jump to a pre-recorded start point and read that record.
+
+ A second class is used to perform pre-parsing of the record. It works
+ by indexing the start of each header field and providing lookup
+ functions for header fields.
+
+ ##################################################################### */
+ /*}}}*/
+// Header section: pkglib
+#ifndef PKGLIB_TAGFILE_H
+#define PKGLIB_TAGFILE_H
+
+#include <pkglib/fileutl.h>
+
+class pkgTagSection
+{
+ const char *Section;
+ const char *Stop;
+
+ // We have a limit of 256 tags per section.
+ unsigned short Indexes[256];
+ unsigned int TagCount;
+
+ public:
+
+ 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);
+ bool Scan(const char *Start,unsigned long MaxLength);
+ inline unsigned long Length() {return Stop - Section;};
+
+ pkgTagSection() : Section(0), Stop(0) {};
+};
+
+class pkgTagFile
+{
+ File Fd;
+ char *Buffer;
+ char *Start;
+ char *End;
+ unsigned long Left;
+
+ bool Fill();
+
+ public:
+
+ bool Step(pkgTagSection &Section);
+
+ pkgTagFile(File &F);
+};
+
+#endif
diff --git a/apt-pkg/version.cc b/apt-pkg/version.cc
new file mode 100644
index 000000000..c02ee5f87
--- /dev/null
+++ b/apt-pkg/version.cc
@@ -0,0 +1,249 @@
+// -*- mode: cpp; mode: fold -*-
+// Description /*{{{*/
+// $Id: version.cc,v 1.1 1998/07/02 02:58:13 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.
+
+ ##################################################################### */
+ /*}}}*/
+// Include Files /*{{{*/
+#include <pkglib/version.h>
+#include <pkglib/pkgcache.h>
+
+#include <stdlib.h>
+ /*}}}*/
+
+// Version::pkgVersion - Default Constructor /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+pkgVersion::pkgVersion()
+{
+}
+ /*}}}*/
+// Version::operator == - Checks if two versions are equal /*{{{*/
+// ---------------------------------------------------------------------
+/* We can't simply perform a string compare because of epochs. */
+bool pkgVersion::operator ==(const pkgVersion &Vrhs) const
+{
+ if (pkgVersionCompare(Value.begin(),Value.end(),
+ Vrhs.Value.begin(),Vrhs.Value.end()) == 0)
+ return true;
+ return false;
+}
+ /*}}}*/
+// Version::operator < - Checks if this is less than another version /*{{{*/
+// ---------------------------------------------------------------------
+/* All other forms of comparision can be built up from this single function.
+ a > b -> b < a
+ a <= b -> !(a > b) -> !(b < a)
+ a >= b -> !(a < b)
+ */
+bool pkgVersion::operator <(const pkgVersion &Vrhs) const
+{
+ if (pkgVersionCompare(Value.begin(),Value.end(),
+ Vrhs.Value.begin(),Vrhs.Value.end()) == -1)
+ return true;
+ return false;
+}
+ /*}}}*/
+// 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);
+}
+ /*}}}*/
+// VersionCompare (op) - Greater than comparison for versions /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+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());
+}
+
+ /*}}}*/
+// VersionCompare - Greater than comparison for versions /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+int pkgVersionCompare(const char *A, const char *AEnd, const char *B,
+ const char *BEnd)
+{
+ // lhs = left hand side, rhs = right hand side
+ const char *lhs = A;
+ const char *rhs = B;
+
+ /* Consider epochs. They need special handling because an epoch
+ must not be compared against the first element of the real version.
+ This works okay when both sides have an epoch but when only one
+ does it must compare the missing epoch to 0 */
+ for (;lhs != AEnd && *lhs != ':'; lhs++);
+ for (;rhs != BEnd && *rhs != ':'; rhs++);
+
+ // Parse the epoch out
+ unsigned long lhsEpoch = 0;
+ unsigned long rhsEpoch = 0;
+ if (lhs != AEnd && *lhs == ':')
+ lhsEpoch = StrToLong(A,lhs);
+ if (rhs != BEnd && *rhs == ':')
+ rhsEpoch = StrToLong(B,rhs);
+ if (lhsEpoch != rhsEpoch)
+ {
+ if (lhsEpoch > rhsEpoch)
+ return 1;
+ 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' */
+ lhs = A;
+ 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 true
+ 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 < !) This is so things like 7.6p2-4 and 7.6-0
+ compare higher as well as . and -. I am not sure how
+ the dpkg code manages to achive the != '-' test, but it
+ is necessary. */
+ int lc = *Slhs;
+ int rc = *Srhs;
+ if (isalpha(lc) == 0 && lc != '-') lc += 256;
+ if (isalpha(rc) == 0 && rc != '-') 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;
+}
+ /*}}}*/
+// 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 pkgOP_LESSEQ:
+ if (Res <= 0)
+ return true;
+ break;
+
+ case pkgOP_GREATEREQ:
+ if (Res >= 0)
+ return true;
+ break;
+
+ case pkgOP_LESS:
+ if (Res < 0)
+ return true;
+ break;
+
+ case pkgOP_GREATER:
+ if (Res > 0)
+ return true;
+ break;
+
+ case pkgOP_EQUALS:
+ if (Res == 0)
+ return true;
+ break;
+
+ case pkgOP_NOTEQUALS:
+ if (Res != 0)
+ return true;
+ break;
+ }
+
+ return false;
+}
+ /*}}}*/
+
diff --git a/apt-pkg/version.h b/apt-pkg/version.h
new file mode 100644
index 000000000..a30246946
--- /dev/null
+++ b/apt-pkg/version.h
@@ -0,0 +1,45 @@
+// -*- mode: cpp; mode: fold -*-
+// Description /*{{{*/
+// $Id: version.h,v 1.1 1998/07/02 02:58:13 jgg Exp $
+/* ######################################################################
+
+ Version - Version string
+
+ This class implements storage and operators for version strings.
+
+ The client is responsible for stripping epochs should it be desired.
+
+ ##################################################################### */
+ /*}}}*/
+// Header section: pkglib
+#ifndef PKGLIB_VERSION_H
+#define PKGLIB_VERSION_H
+
+#include <string>
+
+class pkgVersion
+{
+ string Value;
+
+ public:
+
+ inline operator string () const {return Value;};
+
+ // Assignmnet
+ void operator =(string rhs) {Value = rhs;};
+
+ // Comparitors. STL will provide the rest
+ bool operator ==(const pkgVersion &rhs) const;
+ bool operator <(const pkgVersion &rhs) const;
+
+ pkgVersion();
+ pkgVersion(string Version) : Value(Version) {};
+};
+
+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);
+
+#endif