]> git.saurik.com Git - apt.git/blobdiff - ftparchive/apt-ftparchive.cc
Merge branch 'feature/edit-sources' into debian/sid
[apt.git] / ftparchive / apt-ftparchive.cc
index 055d876d0c568bfac9e62c9cc29126caa0c942dc..2639bc2f6e77f1dc9f87ff0be4dacac713321e0b 100644 (file)
@@ -1,40 +1,40 @@
 // -*- mode: cpp; mode: fold -*-
 // Description                                                         /*{{{*/
 // -*- mode: cpp; mode: fold -*-
 // Description                                                         /*{{{*/
-// $Id: apt-ftparchive.cc,v 1.2 2001/02/20 07:03:18 jgg Exp $
+// $Id: apt-ftparchive.cc,v 1.8.2.3 2004/01/02 22:01:48 mdz Exp $
 /* ######################################################################
 
 /* ######################################################################
 
-   apt-scanpackages - Efficient work-alike for dpkg-scanpackages
+   apt-ftparchive - Efficient work-alike for dpkg-scanpackages
 
    Let contents be disabled from the conf
    
    ##################################################################### */
                                                                        /*}}}*/
 // Include Files                                                       /*{{{*/
 
    Let contents be disabled from the conf
    
    ##################################################################### */
                                                                        /*}}}*/
 // Include Files                                                       /*{{{*/
-#ifdef __GNUG__
-#pragma implementation "apt-ftparchive.h"
-#endif
+#include <config.h>
 
 
-#include "apt-ftparchive.h"
-    
 #include <apt-pkg/error.h>
 #include <apt-pkg/configuration.h>
 #include <apt-pkg/cmndline.h>
 #include <apt-pkg/strutl.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/configuration.h>
 #include <apt-pkg/cmndline.h>
 #include <apt-pkg/strutl.h>
-#include <config.h>
-#include <apti18n.h>
+#include <apt-pkg/init.h>
 #include <algorithm>
 
 #include <algorithm>
 
+#include <climits>
 #include <sys/time.h>
 #include <regex.h>
 
 #include <sys/time.h>
 #include <regex.h>
 
+#include "apt-ftparchive.h"
 #include "contents.h"
 #include "multicompress.h"
 #include "contents.h"
 #include "multicompress.h"
-#include "writer.h"    
+#include "writer.h"
+
+#include <apti18n.h>
                                                                        /*}}}*/
 
                                                                        /*}}}*/
 
-ostream c0out;
-ostream c1out;
-ostream c2out;
+using namespace std;    
+ostream c0out(0);
+ostream c1out(0);
+ostream c2out(0);
 ofstream devnull("/dev/null");
 unsigned Quiet = 0;
 
 ofstream devnull("/dev/null");
 unsigned Quiet = 0;
 
@@ -54,10 +54,19 @@ struct PackageMap
    string PkgFile;
    string BinCacheDB;
    string BinOverride;
    string PkgFile;
    string BinCacheDB;
    string BinOverride;
+   string ExtraOverride;
+
+   // We generate for this given arch
+   string Arch;
    
    // Stuff for the Source File
    string SrcFile;
    string SrcOverride;
    
    // Stuff for the Source File
    string SrcFile;
    string SrcOverride;
+   string SrcExtraOverride;
+
+   // Translation master file
+   bool LongDesc;
+   TranslationWriter *TransWriter;
 
    // Contents 
    string Contents;
 
    // Contents 
    string Contents;
@@ -93,11 +102,13 @@ struct PackageMap
    bool GenPackages(Configuration &Setup,struct CacheDB::Stats &Stats);
    bool GenSources(Configuration &Setup,struct CacheDB::Stats &Stats);
    bool GenContents(Configuration &Setup,
    bool GenPackages(Configuration &Setup,struct CacheDB::Stats &Stats);
    bool GenSources(Configuration &Setup,struct CacheDB::Stats &Stats);
    bool GenContents(Configuration &Setup,
-                   PackageMap *Begin,PackageMap *End,
+                   vector<PackageMap>::iterator Begin,
+                   vector<PackageMap>::iterator End,
                    unsigned long &Left);
    
                    unsigned long &Left);
    
-   PackageMap() : DeLinkLimit(0), Permissions(1), ContentsDone(false), 
-        PkgDone(false), SrcDone(false), ContentsMTime(0) {};
+   PackageMap() : LongDesc(true), TransWriter(NULL), DeLinkLimit(0), Permissions(1),
+                 ContentsDone(false), PkgDone(false), SrcDone(false),
+                 ContentsMTime(0) {};
 };
                                                                        /*}}}*/
 
 };
                                                                        /*}}}*/
 
@@ -126,7 +137,7 @@ void PackageMap::GetGeneral(Configuration &Setup,Configuration &Block)
                       Setup.Find("Default::Packages::Extensions",".deb").c_str());
    
    Permissions = Setup.FindI("Default::FileMode",0644);
                       Setup.Find("Default::Packages::Extensions",".deb").c_str());
    
    Permissions = Setup.FindI("Default::FileMode",0644);
-   
+
    if (FLFile.empty() == false)
       FLFile = flCombine(Setup.Find("Dir::FileListDir"),FLFile);
    
    if (FLFile.empty() == false)
       FLFile = flCombine(Setup.Find("Dir::FileListDir"),FLFile);
    
@@ -153,25 +164,30 @@ bool PackageMap::GenPackages(Configuration &Setup,struct CacheDB::Stats &Stats)
    
    // Create a package writer object.
    PackagesWriter Packages(flCombine(CacheDir,BinCacheDB),
    
    // Create a package writer object.
    PackagesWriter Packages(flCombine(CacheDir,BinCacheDB),
-                          flCombine(OverrideDir,BinOverride));
+                          flCombine(OverrideDir,BinOverride),
+                          flCombine(OverrideDir,ExtraOverride),
+                          Arch);
    if (PkgExt.empty() == false && Packages.SetExts(PkgExt) == false)
    if (PkgExt.empty() == false && Packages.SetExts(PkgExt) == false)
-      return _error->Error("Package extension list is too long");
+      return _error->Error(_("Package extension list is too long"));
    if (_error->PendingError() == true)
    if (_error->PendingError() == true)
-      return _error->Error("Error Processing directory %s",BaseDir.c_str());
+      return _error->Error(_("Error processing directory %s"),BaseDir.c_str());
    
    Packages.PathPrefix = PathPrefix;
    Packages.DirStrip = ArchiveDir;
    Packages.InternalPrefix = flCombine(ArchiveDir,InternalPrefix);
 
    
    Packages.PathPrefix = PathPrefix;
    Packages.DirStrip = ArchiveDir;
    Packages.InternalPrefix = flCombine(ArchiveDir,InternalPrefix);
 
+   Packages.TransWriter = TransWriter;
+   Packages.LongDescription = LongDesc;
+
    Packages.Stats.DeLinkBytes = Stats.DeLinkBytes;
    Packages.DeLinkLimit = DeLinkLimit;
    Packages.Stats.DeLinkBytes = Stats.DeLinkBytes;
    Packages.DeLinkLimit = DeLinkLimit;
-      
+
    // Create a compressor object
    MultiCompress Comp(flCombine(ArchiveDir,PkgFile),
                      PkgCompress,Permissions);
    Packages.Output = Comp.Input;
    if (_error->PendingError() == true)
    // Create a compressor object
    MultiCompress Comp(flCombine(ArchiveDir,PkgFile),
                      PkgCompress,Permissions);
    Packages.Output = Comp.Input;
    if (_error->PendingError() == true)
-      return _error->Error("Error Processing directory %s",BaseDir.c_str());
+      return _error->Error(_("Error processing directory %s"),BaseDir.c_str());
    
    c0out << ' ' << BaseDir << ":" << flush;
    
    
    c0out << ' ' << BaseDir << ":" << flush;
    
@@ -190,11 +206,11 @@ bool PackageMap::GenPackages(Configuration &Setup,struct CacheDB::Stats &Stats)
    Packages.Output = 0;      // Just in case
    
    // Finish compressing
    Packages.Output = 0;      // Just in case
    
    // Finish compressing
-   unsigned long Size;
+   unsigned long long Size;
    if (Comp.Finalize(Size) == false)
    {
       c0out << endl;
    if (Comp.Finalize(Size) == false)
    {
       c0out << endl;
-      return _error->Error("Error Processing directory %s",BaseDir.c_str());
+      return _error->Error(_("Error processing directory %s"),BaseDir.c_str());
    }
    
    if (Size != 0)
    }
    
    if (Size != 0)
@@ -218,8 +234,9 @@ bool PackageMap::GenPackages(Configuration &Setup,struct CacheDB::Stats &Stats)
    
    return !_error->PendingError();
 }
    
    return !_error->PendingError();
 }
+
                                                                        /*}}}*/
                                                                        /*}}}*/
-// PackageMap::GenSources - Actually generate a Package file           /*{{{*/
+// PackageMap::GenSources - Actually generate a Source file            /*{{{*/
 // ---------------------------------------------------------------------
 /* This generates the Sources File described by this object. */
 bool PackageMap::GenSources(Configuration &Setup,struct CacheDB::Stats &Stats)
 // ---------------------------------------------------------------------
 /* This generates the Sources File described by this object. */
 bool PackageMap::GenSources(Configuration &Setup,struct CacheDB::Stats &Stats)
@@ -237,12 +254,14 @@ bool PackageMap::GenSources(Configuration &Setup,struct CacheDB::Stats &Stats)
    SrcDone = true;
    
    // Create a package writer object.
    SrcDone = true;
    
    // Create a package writer object.
-   SourcesWriter Sources(flCombine(OverrideDir,BinOverride),
-                         flCombine(OverrideDir,SrcOverride));
+   SourcesWriter Sources(_config->Find("APT::FTPArchive::DB"),
+                        flCombine(OverrideDir,BinOverride),
+                        flCombine(OverrideDir,SrcOverride),
+                        flCombine(OverrideDir,SrcExtraOverride));
    if (SrcExt.empty() == false && Sources.SetExts(SrcExt) == false)
    if (SrcExt.empty() == false && Sources.SetExts(SrcExt) == false)
-      return _error->Error("Source extension list is too long");
+      return _error->Error(_("Source extension list is too long"));
    if (_error->PendingError() == true)
    if (_error->PendingError() == true)
-      return _error->Error("Error Processing directory %s",BaseDir.c_str());
+      return _error->Error(_("Error processing directory %s"),BaseDir.c_str());
    
    Sources.PathPrefix = PathPrefix;
    Sources.DirStrip = ArchiveDir;
    
    Sources.PathPrefix = PathPrefix;
    Sources.DirStrip = ArchiveDir;
@@ -256,7 +275,7 @@ bool PackageMap::GenSources(Configuration &Setup,struct CacheDB::Stats &Stats)
                      SrcCompress,Permissions);
    Sources.Output = Comp.Input;
    if (_error->PendingError() == true)
                      SrcCompress,Permissions);
    Sources.Output = Comp.Input;
    if (_error->PendingError() == true)
-      return _error->Error("Error Processing directory %s",BaseDir.c_str());
+      return _error->Error(_("Error processing directory %s"),BaseDir.c_str());
 
    c0out << ' ' << BaseDir << ":" << flush;
    
 
    c0out << ' ' << BaseDir << ":" << flush;
    
@@ -274,11 +293,11 @@ bool PackageMap::GenSources(Configuration &Setup,struct CacheDB::Stats &Stats)
    Sources.Output = 0;      // Just in case
    
    // Finish compressing
    Sources.Output = 0;      // Just in case
    
    // Finish compressing
-   unsigned long Size;
+   unsigned long long Size;
    if (Comp.Finalize(Size) == false)
    {
       c0out << endl;
    if (Comp.Finalize(Size) == false)
    {
       c0out << endl;
-      return _error->Error("Error Processing directory %s",BaseDir.c_str());
+      return _error->Error(_("Error processing directory %s"),BaseDir.c_str());
    }
       
    if (Size != 0)
    }
       
    if (Size != 0)
@@ -307,8 +326,9 @@ bool PackageMap::GenSources(Configuration &Setup,struct CacheDB::Stats &Stats)
    It searches the given iterator range for other package files that map
    into this contents file and includes their data as well when building. */
 bool PackageMap::GenContents(Configuration &Setup,
    It searches the given iterator range for other package files that map
    into this contents file and includes their data as well when building. */
 bool PackageMap::GenContents(Configuration &Setup,
-                           PackageMap *Begin,PackageMap *End,
-                           unsigned long &Left)
+                            vector<PackageMap>::iterator Begin,
+                            vector<PackageMap>::iterator End,
+                            unsigned long &Left)
 {
    if (Contents.empty() == true)
       return true;
 {
    if (Contents.empty() == true)
       return true;
@@ -324,9 +344,9 @@ bool PackageMap::GenContents(Configuration &Setup,
    gettimeofday(&StartTime,0);   
    
    // Create a package writer object.
    gettimeofday(&StartTime,0);   
    
    // Create a package writer object.
-   ContentsWriter Contents("");
+   ContentsWriter Contents("", Arch);
    if (PkgExt.empty() == false && Contents.SetExts(PkgExt) == false)
    if (PkgExt.empty() == false && Contents.SetExts(PkgExt) == false)
-      return _error->Error("Package extension list is too long");
+      return _error->Error(_("Package extension list is too long"));
    if (_error->PendingError() == true)
       return false;
 
    if (_error->PendingError() == true)
       return false;
 
@@ -344,11 +364,11 @@ bool PackageMap::GenContents(Configuration &Setup,
       if (_error->PendingError() == true)
         return false;
       
       if (_error->PendingError() == true)
         return false;
       
-      unsigned long Size = Head.Size();
+      unsigned long long Size = Head.Size();
       unsigned char Buf[4096];
       while (Size != 0)
       {
       unsigned char Buf[4096];
       while (Size != 0)
       {
-        unsigned long ToRead = Size;
+        unsigned long long ToRead = Size;
         if (Size > sizeof(Buf))
            ToRead = sizeof(Buf);
         
         if (Size > sizeof(Buf))
            ToRead = sizeof(Buf);
         
@@ -356,7 +376,7 @@ bool PackageMap::GenContents(Configuration &Setup,
            return false;
         
         if (fwrite(Buf,1,ToRead,Comp.Input) != ToRead)
            return false;
         
         if (fwrite(Buf,1,ToRead,Comp.Input) != ToRead)
-           return _error->Errno("fwrite","Error writing header to contents file");
+           return _error->Errno("fwrite",_("Error writing header to contents file"));
         
         Size -= ToRead;
       }            
         
         Size -= ToRead;
       }            
@@ -366,7 +386,7 @@ bool PackageMap::GenContents(Configuration &Setup,
       files associated with this contents file into one great big honking
       memory structure, then dump the sorted version */
    c0out << ' ' << this->Contents << ":" << flush;
       files associated with this contents file into one great big honking
       memory structure, then dump the sorted version */
    c0out << ' ' << this->Contents << ":" << flush;
-   for (PackageMap *I = Begin; I != End; I++)
+   for (vector<PackageMap>::iterator I = Begin; I != End; ++I)
    {
       if (I->Contents != this->Contents)
         continue;
    {
       if (I->Contents != this->Contents)
         continue;
@@ -382,11 +402,11 @@ bool PackageMap::GenContents(Configuration &Setup,
    Contents.Finish();
    
    // Finish compressing
    Contents.Finish();
    
    // Finish compressing
-   unsigned long Size;
+   unsigned long long Size;
    if (Comp.Finalize(Size) == false || _error->PendingError() == true)
    {
       c0out << endl;
    if (Comp.Finalize(Size) == false || _error->PendingError() == true)
    {
       c0out << endl;
-      return _error->Error("Error Processing Contents %s",
+      return _error->Error(_("Error processing contents %s"),
                           this->Contents.c_str());
    }
    
                           this->Contents.c_str());
    }
    
@@ -427,10 +447,12 @@ void LoadTree(vector<PackageMap> &PkgList,Configuration &Setup)
                            "$(DIST)/$(SECTION)/source/");
    string DPkg = Setup.Find("TreeDefault::Packages",
                            "$(DIST)/$(SECTION)/binary-$(ARCH)/Packages");
                            "$(DIST)/$(SECTION)/source/");
    string DPkg = Setup.Find("TreeDefault::Packages",
                            "$(DIST)/$(SECTION)/binary-$(ARCH)/Packages");
+   string DTrans = Setup.Find("TreeDefault::Translation",
+                           "$(DIST)/$(SECTION)/i18n/Translation-en");
    string DIPrfx = Setup.Find("TreeDefault::InternalPrefix",
                            "$(DIST)/$(SECTION)/");
    string DContents = Setup.Find("TreeDefault::Contents",
    string DIPrfx = Setup.Find("TreeDefault::InternalPrefix",
                            "$(DIST)/$(SECTION)/");
    string DContents = Setup.Find("TreeDefault::Contents",
-                           "$(DIST)/Contents-$(ARCH)");
+                           "$(DIST)/$(SECTION)/Contents-$(ARCH)");
    string DContentsH = Setup.Find("TreeDefault::Contents::Header","");
    string DBCache = Setup.Find("TreeDefault::BinCacheDB",
                               "packages-$(ARCH).db");
    string DContentsH = Setup.Find("TreeDefault::Contents::Header","");
    string DBCache = Setup.Find("TreeDefault::BinCacheDB",
                               "packages-$(ARCH).db");
@@ -439,6 +461,12 @@ void LoadTree(vector<PackageMap> &PkgList,Configuration &Setup)
    string DFLFile = Setup.Find("TreeDefault::FileList", "");
    string DSFLFile = Setup.Find("TreeDefault::SourceFileList", "");
 
    string DFLFile = Setup.Find("TreeDefault::FileList", "");
    string DSFLFile = Setup.Find("TreeDefault::SourceFileList", "");
 
+   mode_t const Permissions = Setup.FindI("Default::FileMode",0644);
+
+   bool const LongDescription = Setup.FindB("Default::LongDescription",
+                                       _config->FindB("APT::FTPArchive::LongDescription", true));
+   string const TranslationCompress = Setup.Find("Default::Translation::Compress",". gzip").c_str();
+
    // Process 'tree' type sections
    const Configuration::Item *Top = Setup.Tree("tree");
    for (Top = (Top == 0?0:Top->Child); Top != 0;)
    // Process 'tree' type sections
    const Configuration::Item *Top = Setup.Tree("tree");
    for (Top = (Top == 0?0:Top->Child); Top != 0;)
@@ -447,20 +475,35 @@ void LoadTree(vector<PackageMap> &PkgList,Configuration &Setup)
       string Dist = Top->Tag;
 
       // Parse the sections
       string Dist = Top->Tag;
 
       // Parse the sections
-      const char *Sections = Block.Find("Sections").c_str();
+      string Tmp = Block.Find("Sections");
+      const char *Sections = Tmp.c_str();
       string Section;
       while (ParseQuoteWord(Sections,Section) == true)
       {
       string Section;
       while (ParseQuoteWord(Sections,Section) == true)
       {
-        const char *Archs = Block.Find("Architectures").c_str();
         string Arch;
         string Arch;
+        struct SubstVar const Vars[] = {{"$(DIST)",&Dist},
+                                        {"$(SECTION)",&Section},
+                                        {"$(ARCH)",&Arch},
+                                        {}};
+        mode_t const Perms = Block.FindI("FileMode", Permissions);
+        bool const LongDesc = Block.FindB("LongDescription", LongDescription);
+        TranslationWriter *TransWriter;
+        if (DTrans.empty() == false && LongDesc == false)
+        {
+           string const TranslationFile = flCombine(Setup.FindDir("Dir::ArchiveDir"),
+                       SubstVar(Block.Find("Translation", DTrans.c_str()), Vars));
+           string const TransCompress = Block.Find("Translation::Compress", TranslationCompress);
+           TransWriter = new TranslationWriter(TranslationFile, TransCompress, Perms);
+        }
+        else
+           TransWriter = NULL;
+
+        string const Tmp2 = Block.Find("Architectures");
+        const char *Archs = Tmp2.c_str();
         while (ParseQuoteWord(Archs,Arch) == true)
         {
         while (ParseQuoteWord(Archs,Arch) == true)
         {
-           struct SubstVar Vars[] = {{"$(DIST)",&Dist},
-                                     {"$(SECTION)",&Section},
-                                     {"$(ARCH)",&Arch},
-                                     {}};
            PackageMap Itm;
            PackageMap Itm;
-           
+           Itm.Permissions = Perms;
            Itm.BinOverride = SubstVar(Block.Find("BinOverride"),Vars);
            Itm.InternalPrefix = SubstVar(Block.Find("InternalPrefix",DIPrfx.c_str()),Vars);
 
            Itm.BinOverride = SubstVar(Block.Find("BinOverride"),Vars);
            Itm.InternalPrefix = SubstVar(Block.Find("InternalPrefix",DIPrfx.c_str()),Vars);
 
@@ -471,6 +514,7 @@ void LoadTree(vector<PackageMap> &PkgList,Configuration &Setup)
               Itm.SrcFile = SubstVar(Block.Find("Sources",DSources.c_str()),Vars);
               Itm.Tag = SubstVar("$(DIST)/$(SECTION)/source",Vars);
               Itm.FLFile = SubstVar(Block.Find("SourceFileList",DSFLFile.c_str()),Vars);
               Itm.SrcFile = SubstVar(Block.Find("Sources",DSources.c_str()),Vars);
               Itm.Tag = SubstVar("$(DIST)/$(SECTION)/source",Vars);
               Itm.FLFile = SubstVar(Block.Find("SourceFileList",DSFLFile.c_str()),Vars);
+              Itm.SrcExtraOverride = SubstVar(Block.Find("SrcExtraOverride"),Vars);
            }
            else
            {
            }
            else
            {
@@ -478,14 +522,25 @@ void LoadTree(vector<PackageMap> &PkgList,Configuration &Setup)
               Itm.BaseDir = SubstVar(Block.Find("Directory",DDir.c_str()),Vars);
               Itm.PkgFile = SubstVar(Block.Find("Packages",DPkg.c_str()),Vars);
               Itm.Tag = SubstVar("$(DIST)/$(SECTION)/$(ARCH)",Vars);
               Itm.BaseDir = SubstVar(Block.Find("Directory",DDir.c_str()),Vars);
               Itm.PkgFile = SubstVar(Block.Find("Packages",DPkg.c_str()),Vars);
               Itm.Tag = SubstVar("$(DIST)/$(SECTION)/$(ARCH)",Vars);
+              Itm.Arch = Arch;
+              Itm.LongDesc = LongDesc;
+              if (TransWriter != NULL)
+              {
+                 TransWriter->IncreaseRefCounter();
+                 Itm.TransWriter = TransWriter;
+              }
               Itm.Contents = SubstVar(Block.Find("Contents",DContents.c_str()),Vars);
               Itm.ContentsHead = SubstVar(Block.Find("Contents::Header",DContentsH.c_str()),Vars);
               Itm.FLFile = SubstVar(Block.Find("FileList",DFLFile.c_str()),Vars);
               Itm.Contents = SubstVar(Block.Find("Contents",DContents.c_str()),Vars);
               Itm.ContentsHead = SubstVar(Block.Find("Contents::Header",DContentsH.c_str()),Vars);
               Itm.FLFile = SubstVar(Block.Find("FileList",DFLFile.c_str()),Vars);
+              Itm.ExtraOverride = SubstVar(Block.Find("ExtraOverride"),Vars);
            }
 
            Itm.GetGeneral(Setup,Block);
            PkgList.push_back(Itm);
         }
            }
 
            Itm.GetGeneral(Setup,Block);
            PkgList.push_back(Itm);
         }
+        // we didn't use this TransWriter, so we can release it
+        if (TransWriter != NULL && TransWriter->GetRefCounter() == 0)
+           delete TransWriter;
       }
       
       Top = Top->Next;
       }
       
       Top = Top->Next;
@@ -497,6 +552,8 @@ void LoadTree(vector<PackageMap> &PkgList,Configuration &Setup)
 /* */
 void LoadBinDir(vector<PackageMap> &PkgList,Configuration &Setup)
 {
 /* */
 void LoadBinDir(vector<PackageMap> &PkgList,Configuration &Setup)
 {
+   mode_t const Permissions = Setup.FindI("Default::FileMode",0644);
+
    // Process 'bindirectory' type sections
    const Configuration::Item *Top = Setup.Tree("bindirectory");
    for (Top = (Top == 0?0:Top->Child); Top != 0;)
    // Process 'bindirectory' type sections
    const Configuration::Item *Top = Setup.Tree("bindirectory");
    for (Top = (Top == 0?0:Top->Child); Top != 0;)
@@ -508,12 +565,15 @@ void LoadBinDir(vector<PackageMap> &PkgList,Configuration &Setup)
       Itm.SrcFile = Block.Find("Sources");
       Itm.BinCacheDB = Block.Find("BinCacheDB");
       Itm.BinOverride = Block.Find("BinOverride");
       Itm.SrcFile = Block.Find("Sources");
       Itm.BinCacheDB = Block.Find("BinCacheDB");
       Itm.BinOverride = Block.Find("BinOverride");
+      Itm.ExtraOverride = Block.Find("ExtraOverride");
+      Itm.SrcExtraOverride = Block.Find("SrcExtraOverride");
       Itm.SrcOverride = Block.Find("SrcOverride");
       Itm.BaseDir = Top->Tag;
       Itm.FLFile = Block.Find("FileList");
       Itm.InternalPrefix = Block.Find("InternalPrefix",Top->Tag.c_str());
       Itm.Contents = Block.Find("Contents");
       Itm.ContentsHead = Block.Find("Contents::Header");
       Itm.SrcOverride = Block.Find("SrcOverride");
       Itm.BaseDir = Top->Tag;
       Itm.FLFile = Block.Find("FileList");
       Itm.InternalPrefix = Block.Find("InternalPrefix",Top->Tag.c_str());
       Itm.Contents = Block.Find("Contents");
       Itm.ContentsHead = Block.Find("Contents::Header");
+      Itm.Permissions = Block.FindI("FileMode", Permissions);
       
       Itm.GetGeneral(Setup,Block);
       PkgList.push_back(Itm);
       
       Itm.GetGeneral(Setup,Block);
       PkgList.push_back(Itm);
@@ -528,16 +588,17 @@ void LoadBinDir(vector<PackageMap> &PkgList,Configuration &Setup)
 /* */
 bool ShowHelp(CommandLine &CmdL)
 {
 /* */
 bool ShowHelp(CommandLine &CmdL)
 {
-   ioprintf(cout,_("%s %s for %s %s compiled on %s %s\n"),PACKAGE,VERSION,
-           COMMON_OS,COMMON_CPU,__DATE__,__TIME__);
+   ioprintf(cout,_("%s %s for %s compiled on %s %s\n"),PACKAGE,PACKAGE_VERSION,
+           COMMON_ARCH,__DATE__,__TIME__);
    if (_config->FindB("version") == true)
       return true;
 
    cout << 
    if (_config->FindB("version") == true)
       return true;
 
    cout << 
-      "Usage: apt-ftparchive [options] command\n"
-      "Commands: packges binarypath [overridefile [pathprefix]]\n"
+    _("Usage: apt-ftparchive [options] command\n"
+      "Commands: packages binarypath [overridefile [pathprefix]]\n"
       "          sources srcpath [overridefile [pathprefix]]\n"
       "          contents path\n"
       "          sources srcpath [overridefile [pathprefix]]\n"
       "          contents path\n"
+      "          release path\n"
       "          generate config [groups]\n"
       "          clean config\n"
       "\n"
       "          generate config [groups]\n"
       "          clean config\n"
       "\n"
@@ -555,9 +616,9 @@ bool ShowHelp(CommandLine &CmdL)
       "\n"
       "The 'packages' and 'sources' command should be run in the root of the\n"
       "tree. BinaryPath should point to the base of the recursive search and \n"
       "\n"
       "The 'packages' and 'sources' command should be run in the root of the\n"
       "tree. BinaryPath should point to the base of the recursive search and \n"
-      "override file should contian the override flags. Pathprefix is\n"
+      "override file should contain the override flags. Pathprefix is\n"
       "appended to the filename fields if present. Example usage from the \n"
       "appended to the filename fields if present. Example usage from the \n"
-      "debian archive:\n"
+      "Debian archive:\n"
       "   apt-ftparchive packages dists/potato/main/binary-i386/ > \\\n"
       "               dists/potato/main/binary-i386/Packages\n"
       "\n"
       "   apt-ftparchive packages dists/potato/main/binary-i386/ > \\\n"
       "               dists/potato/main/binary-i386/Packages\n"
       "\n"
@@ -570,7 +631,7 @@ bool ShowHelp(CommandLine &CmdL)
       "  --no-delink Enable delinking debug mode\n"
       "  --contents  Control contents file generation\n"
       "  -c=?  Read this configuration file\n"
       "  --no-delink Enable delinking debug mode\n"
       "  --contents  Control contents file generation\n"
       "  -c=?  Read this configuration file\n"
-      "  -o=?  Set an arbitary configuration option" << endl;
+      "  -o=?  Set an arbitrary configuration option") << endl;
    
    return true;
 }
    
    return true;
 }
@@ -589,7 +650,7 @@ bool SimpleGenPackages(CommandLine &CmdL)
    
    // Create a package writer object.
    PackagesWriter Packages(_config->Find("APT::FTPArchive::DB"),
    
    // Create a package writer object.
    PackagesWriter Packages(_config->Find("APT::FTPArchive::DB"),
-                          Override);   
+                          Override, "", _config->Find("APT::FTPArchive::Architecture"));
    if (_error->PendingError() == true)
       return false;
    
    if (_error->PendingError() == true)
       return false;
    
@@ -612,7 +673,7 @@ bool SimpleGenContents(CommandLine &CmdL)
       return ShowHelp(CmdL);
    
    // Create a package writer object.
       return ShowHelp(CmdL);
    
    // Create a package writer object.
-   ContentsWriter Contents(_config->Find("APT::FTPArchive::DB"));
+   ContentsWriter Contents(_config->Find("APT::FTPArchive::DB"), _config->Find("APT::FTPArchive::Architecture"));
    if (_error->PendingError() == true)
       return false;
    
    if (_error->PendingError() == true)
       return false;
    
@@ -645,7 +706,7 @@ bool SimpleGenSources(CommandLine &CmdL)
                             SOverride.c_str());
        
    // Create a package writer object.
                             SOverride.c_str());
        
    // Create a package writer object.
-   SourcesWriter Sources(Override,SOverride);
+   SourcesWriter Sources(_config->Find("APT::FTPArchive::DB"),Override,SOverride);
    if (_error->PendingError() == true)
       return false;
    
    if (_error->PendingError() == true)
       return false;
    
@@ -658,6 +719,30 @@ bool SimpleGenSources(CommandLine &CmdL)
 
    return true;
 }
 
    return true;
 }
+                                                                       /*}}}*/
+// SimpleGenRelease - Generate a Release file for a directory tree     /*{{{*/
+// ---------------------------------------------------------------------
+bool SimpleGenRelease(CommandLine &CmdL)
+{
+   if (CmdL.FileSize() < 2)
+      return ShowHelp(CmdL);
+
+   string Dir = CmdL.FileList[1];
+
+   ReleaseWriter Release("");
+   Release.DirStrip = Dir;
+
+   if (_error->PendingError() == true)
+      return false;
+
+   if (Release.RecursiveScan(Dir) == false)
+      return false;
+
+   Release.Finish();
+
+   return true;
+}
+
                                                                        /*}}}*/
 // Generate - Full generate, using a config file                       /*{{{*/
 // ---------------------------------------------------------------------
                                                                        /*}}}*/
 // Generate - Full generate, using a config file                       /*{{{*/
 // ---------------------------------------------------------------------
@@ -687,10 +772,10 @@ bool Generate(CommandLine &CmdL)
    // Generate packages
    if (CmdL.FileSize() <= 2)
    {
    // Generate packages
    if (CmdL.FileSize() <= 2)
    {
-      for (PackageMap *I = PkgList.begin(); I != PkgList.end(); I++)
+      for (vector<PackageMap>::iterator I = PkgList.begin(); I != PkgList.end(); ++I)
         if (I->GenPackages(Setup,Stats) == false)
            _error->DumpErrors();
         if (I->GenPackages(Setup,Stats) == false)
            _error->DumpErrors();
-      for (PackageMap *I = PkgList.begin(); I != PkgList.end(); I++)
+      for (vector<PackageMap>::iterator I = PkgList.begin(); I != PkgList.end(); ++I)
         if (I->GenSources(Setup,SrcStats) == false)
            _error->DumpErrors();
    }
         if (I->GenSources(Setup,SrcStats) == false)
            _error->DumpErrors();
    }
@@ -699,13 +784,13 @@ bool Generate(CommandLine &CmdL)
       // Make a choice list out of the package list..
       RxChoiceList *List = new RxChoiceList[2*PkgList.size()+1];
       RxChoiceList *End = List;
       // Make a choice list out of the package list..
       RxChoiceList *List = new RxChoiceList[2*PkgList.size()+1];
       RxChoiceList *End = List;
-      for (PackageMap *I = PkgList.begin(); I != PkgList.end(); I++)
+      for (vector<PackageMap>::iterator I = PkgList.begin(); I != PkgList.end(); ++I)
       {
       {
-        End->UserData = I;
+        End->UserData = &(*I);
         End->Str = I->BaseDir.c_str();
         End++;
         
         End->Str = I->BaseDir.c_str();
         End++;
         
-        End->UserData = I;
+        End->UserData = &(*I);
         End->Str = I->Tag.c_str();
         End++;  
       }
         End->Str = I->Tag.c_str();
         End++;  
       }
@@ -715,7 +800,7 @@ bool Generate(CommandLine &CmdL)
       if (RegexChoice(List,CmdL.FileList + 2,CmdL.FileList + CmdL.FileSize()) == 0)
       {
         delete [] List;
       if (RegexChoice(List,CmdL.FileList + 2,CmdL.FileList + CmdL.FileSize()) == 0)
       {
         delete [] List;
-        return _error->Error("No selections matched");
+        return _error->Error(_("No selections matched"));
       }
       _error->DumpErrors();
       
       }
       _error->DumpErrors();
       
@@ -747,15 +832,20 @@ bool Generate(CommandLine &CmdL)
       
       delete [] List;
    }
       
       delete [] List;
    }
-   
+
+   // close the Translation master files
+   for (vector<PackageMap>::reverse_iterator I = PkgList.rbegin(); I != PkgList.rend(); ++I)
+      if (I->TransWriter != NULL && I->TransWriter->DecreaseRefCounter() == 0)
+        delete I->TransWriter;
+
    if (_config->FindB("APT::FTPArchive::Contents",true) == false)
       return true;
    
    if (_config->FindB("APT::FTPArchive::Contents",true) == false)
       return true;
    
-   c1out << "Done Packages, Starting contents." << endl;
+   c1out << "Packages done, Starting contents." << endl;
 
    // Sort the contents file list by date
    string ArchiveDir = Setup.FindDir("Dir::ArchiveDir");
 
    // Sort the contents file list by date
    string ArchiveDir = Setup.FindDir("Dir::ArchiveDir");
-   for (PackageMap *I = PkgList.begin(); I != PkgList.end(); I++)
+   for (vector<PackageMap>::iterator I = PkgList.begin(); I != PkgList.end(); ++I)
    {
       struct stat A;
       if (MultiCompress::GetStat(flCombine(ArchiveDir,I->Contents),
    {
       struct stat A;
       if (MultiCompress::GetStat(flCombine(ArchiveDir,I->Contents),
@@ -772,7 +862,7 @@ bool Generate(CommandLine &CmdL)
       hashes of the .debs this means they have not changed either so the 
       contents must be up to date. */
    unsigned long MaxContentsChange = Setup.FindI("Default::MaxContentsChange",UINT_MAX)*1024;
       hashes of the .debs this means they have not changed either so the 
       contents must be up to date. */
    unsigned long MaxContentsChange = Setup.FindI("Default::MaxContentsChange",UINT_MAX)*1024;
-   for (PackageMap *I = PkgList.begin(); I != PkgList.end(); I++)
+   for (vector<PackageMap>::iterator I = PkgList.begin(); I != PkgList.end(); ++I)
    {
       // This record is not relevent
       if (I->ContentsDone == true ||
    {
       // This record is not relevent
       if (I->ContentsDone == true ||
@@ -788,7 +878,7 @@ bool Generate(CommandLine &CmdL)
       {
         if (MultiCompress::GetStat(flCombine(ArchiveDir,I->PkgFile),I->PkgCompress,B) == false)
         {
       {
         if (MultiCompress::GetStat(flCombine(ArchiveDir,I->PkgFile),I->PkgCompress,B) == false)
         {
-           _error->Warning("Some files are missing in the package file group `%s'",I->PkgFile.c_str());
+           _error->Warning(_("Some files are missing in the package file group `%s'"),I->PkgFile.c_str());
            continue;
         }
         
            continue;
         }
         
@@ -840,7 +930,7 @@ bool Clean(CommandLine &CmdL)
 
    string CacheDir = Setup.FindDir("Dir::CacheDir");
    
 
    string CacheDir = Setup.FindDir("Dir::CacheDir");
    
-   for (PackageMap *I = PkgList.begin(); I != PkgList.end(); )
+   for (vector<PackageMap>::iterator I = PkgList.begin(); I != PkgList.end(); )
    {
       c0out << I->BinCacheDB << endl;
       CacheDB DB(flCombine(CacheDir,I->BinCacheDB));
    {
       c0out << I->BinCacheDB << endl;
       CacheDB DB(flCombine(CacheDir,I->BinCacheDB));
@@ -848,7 +938,7 @@ bool Clean(CommandLine &CmdL)
         _error->DumpErrors();
       
       string CacheDB = I->BinCacheDB;
         _error->DumpErrors();
       
       string CacheDB = I->BinCacheDB;
-      for (; I != PkgList.end() && I->BinCacheDB == CacheDB; I++);
+      for (; I != PkgList.end() && I->BinCacheDB == CacheDB; ++I);
    }
    
    return true;
    }
    
    return true;
@@ -857,9 +947,12 @@ bool Clean(CommandLine &CmdL)
 
 int main(int argc, const char *argv[])
 {
 
 int main(int argc, const char *argv[])
 {
+   setlocale(LC_ALL, "");
    CommandLine::Args Args[] = {
       {'h',"help","help",0},
       {0,"md5","APT::FTPArchive::MD5",0},
    CommandLine::Args Args[] = {
       {'h',"help","help",0},
       {0,"md5","APT::FTPArchive::MD5",0},
+      {0,"sha1","APT::FTPArchive::SHA1",0},
+      {0,"sha256","APT::FTPArchive::SHA256",0},
       {'v',"version","version",0},
       {'d',"db","APT::FTPArchive::DB",CommandLine::HasArg},
       {'s',"source-override","APT::FTPArchive::SourceOverride",CommandLine::HasArg},
       {'v',"version","version",0},
       {'d',"db","APT::FTPArchive::DB",CommandLine::HasArg},
       {'s',"source-override","APT::FTPArchive::SourceOverride",CommandLine::HasArg},
@@ -868,12 +961,14 @@ int main(int argc, const char *argv[])
       {0,"delink","APT::FTPArchive::DeLinkAct",0},
       {0,"readonly","APT::FTPArchive::ReadOnlyDB",0},
       {0,"contents","APT::FTPArchive::Contents",0},
       {0,"delink","APT::FTPArchive::DeLinkAct",0},
       {0,"readonly","APT::FTPArchive::ReadOnlyDB",0},
       {0,"contents","APT::FTPArchive::Contents",0},
+      {'a',"arch","APT::FTPArchive::Architecture",CommandLine::HasArg},
       {'c',"config-file",0,CommandLine::ConfigFile},
       {'o',"option",0,CommandLine::ArbItem},
       {0,0,0,0}};
    CommandLine::Dispatch Cmds[] = {{"packages",&SimpleGenPackages},
                                    {"contents",&SimpleGenContents},
                                    {"sources",&SimpleGenSources},
       {'c',"config-file",0,CommandLine::ConfigFile},
       {'o',"option",0,CommandLine::ArbItem},
       {0,0,0,0}};
    CommandLine::Dispatch Cmds[] = {{"packages",&SimpleGenPackages},
                                    {"contents",&SimpleGenContents},
                                    {"sources",&SimpleGenSources},
+                                   {"release",&SimpleGenRelease},
                                    {"generate",&Generate},
                                    {"clean",&Clean},
                                   {"help",&ShowHelp},
                                    {"generate",&Generate},
                                    {"clean",&Clean},
                                   {"help",&ShowHelp},
@@ -881,7 +976,7 @@ int main(int argc, const char *argv[])
 
    // Parse the command line and initialize the package library
    CommandLine CmdL(Args,_config);
 
    // Parse the command line and initialize the package library
    CommandLine CmdL(Args,_config);
-   if (CmdL.Parse(argc,argv) == false)
+   if (pkgInitConfig(*_config) == false || CmdL.Parse(argc,argv) == false)
    {
       _error->DumpErrors();
       return 100;
    {
       _error->DumpErrors();
       return 100;
@@ -897,9 +992,9 @@ int main(int argc, const char *argv[])
    }
    
    // Setup the output streams
    }
    
    // Setup the output streams
-   c0out.rdbuf(cout.rdbuf());
-   c1out.rdbuf(cout.rdbuf());
-   c2out.rdbuf(cout.rdbuf());
+   c0out.rdbuf(clog.rdbuf());
+   c1out.rdbuf(clog.rdbuf());
+   c2out.rdbuf(clog.rdbuf());
    Quiet = _config->FindI("quiet",0);
    if (Quiet > 0)
       c0out.rdbuf(devnull.rdbuf());
    Quiet = _config->FindI("quiet",0);
    if (Quiet > 0)
       c0out.rdbuf(devnull.rdbuf());