* apt-pkg/contrib/configuration.cc:
[ntk/apt.git] / apt-pkg / contrib / configuration.cc
index 4e8586e..ff80dfa 100644 (file)
    ##################################################################### */
                                                                        /*}}}*/
 // Include files                                                       /*{{{*/
+#include <config.h>
+
 #include <apt-pkg/configuration.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/strutl.h>
 #include <apt-pkg/fileutl.h>
-#include <apti18n.h>
 
 #include <vector>
-#include <algorithm>
 #include <fstream>
 #include <iostream>
-    
-#include <stdio.h>
-#include <dirent.h>
-#include <sys/stat.h>
-#include <unistd.h>
+
+#include <apti18n.h>
 
 using namespace std;
                                                                        /*}}}*/
@@ -85,7 +82,7 @@ Configuration::~Configuration()
 /* This will lookup a single item by name below another item. It is a 
    helper function for the main lookup function */
 Configuration::Item *Configuration::Lookup(Item *Head,const char *S,
-                                          unsigned long Len,bool Create)
+                                          unsigned long const &Len,bool const &Create)
 {
    int Res = 1;
    Item *I = Head->Child;
@@ -118,7 +115,7 @@ Configuration::Item *Configuration::Lookup(Item *Head,const char *S,
 // ---------------------------------------------------------------------
 /* This performs a fully scoped lookup of a given name, possibly creating
    new items */
-Configuration::Item *Configuration::Lookup(const char *Name,bool Create)
+Configuration::Item *Configuration::Lookup(const char *Name,bool const &Create)
 {
    if (Name == 0)
       return Root->Child;
@@ -188,8 +185,14 @@ string Configuration::FindFile(const char *Name,const char *Default) const
    }
    
    string val = Itm->Value;
-   while (Itm->Parent != 0 && Itm->Parent->Value.empty() == false)
-   {    
+   while (Itm->Parent != 0)
+   {
+      if (Itm->Parent->Value.empty() == true)
+      {
+        Itm = Itm->Parent;
+        continue;
+      }
+
       // Absolute
       if (val.length() >= 1 && val[0] == '/')
          break;
@@ -245,7 +248,7 @@ vector<string> Configuration::FindVector(const char *Name) const
 // Configuration::FindI - Find an integer value                                /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-int Configuration::FindI(const char *Name,int Default) const
+int Configuration::FindI(const char *Name,int const &Default) const
 {
    const Item *Itm = Lookup(Name);
    if (Itm == 0 || Itm->Value.empty() == true)
@@ -262,7 +265,7 @@ int Configuration::FindI(const char *Name,int Default) const
 // Configuration::FindB - Find a boolean type                          /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-bool Configuration::FindB(const char *Name,bool Default) const
+bool Configuration::FindB(const char *Name,bool const &Default) const
 {
    const Item *Itm = Lookup(Name);
    if (Itm == 0 || Itm->Value.empty() == true)
@@ -324,6 +327,19 @@ void Configuration::CndSet(const char *Name,const string &Value)
       Itm->Value = Value;
 }
                                                                        /*}}}*/
+// Configuration::Set - Set an integer value                           /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+void Configuration::CndSet(const char *Name,int const Value)
+{
+   Item *Itm = Lookup(Name,true);
+   if (Itm == 0 || Itm->Value.empty() == false)
+      return;
+   char S[300];
+   snprintf(S,sizeof(S),"%i",Value);
+   Itm->Value = S;
+}
+                                                                       /*}}}*/
 // Configuration::Set - Set a value                                    /*{{{*/
 // ---------------------------------------------------------------------
 /* */
@@ -338,7 +354,7 @@ void Configuration::Set(const char *Name,const string &Value)
 // Configuration::Set - Set an integer value                           /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-void Configuration::Set(const char *Name,int Value)
+void Configuration::Set(const char *Name,int const &Value)
 {
    Item *Itm = Lookup(Name,true);
    if (Itm == 0)
@@ -351,7 +367,7 @@ void Configuration::Set(const char *Name,int Value)
 // Configuration::Clear - Clear an single value from a list            /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-void Configuration::Clear(const string Name, int Value)
+void Configuration::Clear(string const &Name, int const &Value)
 {
    char S[300];
    snprintf(S,sizeof(S),"%i",Value);
@@ -361,7 +377,7 @@ void Configuration::Clear(const string Name, int Value)
 // Configuration::Clear - Clear an single value from a list            /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-void Configuration::Clear(const string Name, string Value)
+void Configuration::Clear(string const &Name, string const &Value)
 {
    Item *Top = Lookup(Name.c_str(),false);
    if (Top == 0 || Top->Child == 0)
@@ -392,7 +408,7 @@ void Configuration::Clear(const string Name, string Value)
 // Configuration::Clear - Clear an entire tree                         /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-void Configuration::Clear(string Name)
+void Configuration::Clear(string const &Name)
 {
    Item *Top = Lookup(Name.c_str(),false);
    if (Top == 0) 
@@ -466,24 +482,80 @@ bool Configuration::ExistsAny(const char *Name) const
 /* Dump the entire configuration space */
 void Configuration::Dump(ostream& str)
 {
-   /* Write out all of the configuration directives by walking the 
+   Dump(str, NULL, "%f \"%v\";\n", true);
+}
+void Configuration::Dump(ostream& str, char const * const root,
+                        char const * const formatstr, bool const emptyValue)
+{
+   const Configuration::Item* Top = Tree(root);
+   if (Top == 0)
+      return;
+   const Configuration::Item* const Root = (root == NULL) ? NULL : Top;
+   std::vector<std::string> const format = VectorizeString(formatstr, '%');
+
+   /* Write out all of the configuration directives by walking the
       configuration tree */
-   const Configuration::Item *Top = Tree(0);
-   for (; Top != 0;)
-   {
-      str << Top->FullTag() << " \"" << Top->Value << "\";" << endl;
-      
+   do {
+      if (emptyValue == true || Top->Value.empty() == emptyValue)
+      {
+        std::vector<std::string>::const_iterator f = format.begin();
+        str << *f;
+        for (++f; f != format.end(); ++f)
+        {
+           if (f->empty() == true)
+           {
+              ++f;
+              str << '%' << *f;
+              continue;
+           }
+           char const type = (*f)[0];
+           if (type == 'f')
+              str << Top->FullTag();
+           else if (type == 't')
+              str << Top->Tag;
+           else if (type == 'v')
+              str << Top->Value;
+           else if (type == 'F')
+              str << QuoteString(Top->FullTag(), "=\"\n");
+           else if (type == 'T')
+              str << QuoteString(Top->Tag, "=\"\n");
+           else if (type == 'V')
+              str << QuoteString(Top->Value, "=\"\n");
+           else if (type == 'n')
+              str << "\n";
+           else if (type == 'N')
+              str << "\t";
+           else
+              str << '%' << type;
+           str << f->c_str() + 1;
+        }
+      }
+
       if (Top->Child != 0)
       {
         Top = Top->Child;
         continue;
       }
-      
+
       while (Top != 0 && Top->Next == 0)
         Top = Top->Parent;
       if (Top != 0)
         Top = Top->Next;
-   }
+
+      if (Root != NULL)
+      {
+        const Configuration::Item* I = Top;
+        while(I != 0)
+        {
+           if (I == Root)
+              break;
+           else
+              I = I->Parent;
+        }
+        if (I == 0)
+           break;
+      }
+   } while (Top != 0);
 }
                                                                        /*}}}*/
 
@@ -507,8 +579,8 @@ string Configuration::Item::FullTag(const Item *Stop) const
    sections like 'zone "foo.org" { .. };' This causes each section to be
    added in with a tag like "zone::foo.org" instead of being split 
    tag/value. AsSectional enables Sectional parsing.*/
-bool ReadConfigFile(Configuration &Conf,const string &FName,bool AsSectional,
-                   unsigned Depth)
+bool ReadConfigFile(Configuration &Conf,const string &FName,bool const &AsSectional,
+                   unsigned const &Depth)
 {   
    // Open the stream for reading
    ifstream F(FName.c_str(),ios::in); 
@@ -665,9 +737,9 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool AsSectional,
            // Put the last fragment into the buffer
            std::string::const_iterator NonWhitespaceStart = Start;
            std::string::const_iterator NonWhitespaceStop = I;
-           for (; NonWhitespaceStart != I && isspace(*NonWhitespaceStart) != 0; NonWhitespaceStart++)
+           for (; NonWhitespaceStart != I && isspace(*NonWhitespaceStart) != 0; ++NonWhitespaceStart)
              ;
-           for (; NonWhitespaceStop != NonWhitespaceStart && isspace(NonWhitespaceStop[-1]) != 0; NonWhitespaceStop--)
+           for (; NonWhitespaceStop != NonWhitespaceStart && isspace(NonWhitespaceStop[-1]) != 0; --NonWhitespaceStop)
              ;
            if (LineBuffer.empty() == false && NonWhitespaceStop - NonWhitespaceStart != 0)
               LineBuffer += ' ';
@@ -779,6 +851,8 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool AsSectional,
               else
                  return _error->Error(_("Syntax error %s:%u: Unsupported directive '%s'"),FName.c_str(),CurLine,Tag.c_str());
            }
+           else if (Tag.empty() == true && NoWord == false && Word == "#clear")
+              return _error->Error(_("Syntax error %s:%u: clear directive requires an option tree as argument"),FName.c_str(),CurLine);
            else
            {
               // Set the item in the configuration class
@@ -835,44 +909,67 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool AsSectional,
 // ReadConfigDir - Read a directory of config files                    /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-bool ReadConfigDir(Configuration &Conf,const string &Dir,bool AsSectional,
-                  unsigned Depth)
-{   
-   DIR *D = opendir(Dir.c_str());
-   if (D == 0)
-      return _error->Errno("opendir",_("Unable to read %s"),Dir.c_str());
-
-   vector<string> List;
-   
-   for (struct dirent *Ent = readdir(D); Ent != 0; Ent = readdir(D))
-   {
-      if (Ent->d_name[0] == '.')
-        continue;
-      
-      // Skip bad file names ala run-parts
-      const char *C = Ent->d_name;
-      for (; *C != 0; C++)
-        if (isalpha(*C) == 0 && isdigit(*C) == 0 && *C != '_' && *C != '-')
-           break;
-      if (*C != 0)
-        continue;
-      
-      // Make sure it is a file and not something else
-      string File = flCombine(Dir,Ent->d_name);
-      struct stat St;
-      if (stat(File.c_str(),&St) != 0 || S_ISREG(St.st_mode) == 0)
-        continue;
-      
-      List.push_back(File);      
-   }   
-   closedir(D);
-   
-   sort(List.begin(),List.end());
+bool ReadConfigDir(Configuration &Conf,const string &Dir,
+                  bool const &AsSectional, unsigned const &Depth)
+{
+   vector<string> const List = GetListOfFilesInDir(Dir, "conf", true, true);
 
    // Read the files
-   for (vector<string>::const_iterator I = List.begin(); I != List.end(); I++)
+   for (vector<string>::const_iterator I = List.begin(); I != List.end(); ++I)
       if (ReadConfigFile(Conf,*I,AsSectional,Depth) == false)
         return false;
    return true;
 }
                                                                        /*}}}*/
+// MatchAgainstConfig Constructor                                      /*{{{*/
+Configuration::MatchAgainstConfig::MatchAgainstConfig(char const * Config)
+{
+   std::vector<std::string> const strings = _config->FindVector(Config);
+   for (std::vector<std::string>::const_iterator s = strings.begin();
+       s != strings.end(); ++s)
+   {
+      regex_t *p = new regex_t;
+      if (regcomp(p, s->c_str(), REG_EXTENDED | REG_ICASE | REG_NOSUB) == 0)
+        patterns.push_back(p);
+      else
+      {
+        regfree(p);
+        delete p;
+        _error->Warning("Invalid regular expression '%s' in configuration "
+                         "option '%s' will be ignored.",
+                         s->c_str(), Config);
+        continue;
+      }
+   }
+   if (strings.size() == 0)
+      patterns.push_back(NULL);
+}
+                                                                       /*}}}*/
+// MatchAgainstConfig Destructor                                       /*{{{*/
+Configuration::MatchAgainstConfig::~MatchAgainstConfig()
+{
+   clearPatterns();
+}
+void Configuration::MatchAgainstConfig::clearPatterns()
+{
+   for(std::vector<regex_t *>::const_iterator p = patterns.begin();
+       p != patterns.end(); ++p)
+   {
+      if (*p == NULL) continue;
+      regfree(*p);
+      delete *p;
+   }
+   patterns.clear();
+}
+                                                                       /*}}}*/
+// MatchAgainstConfig::Match - returns true if a pattern matches       /*{{{*/
+bool Configuration::MatchAgainstConfig::Match(char const * str) const
+{
+   for(std::vector<regex_t *>::const_iterator p = patterns.begin();
+       p != patterns.end(); ++p)
+      if (*p != NULL && regexec(*p, str, 0, 0, 0) == 0)
+        return true;
+
+   return false;
+}
+                                                                       /*}}}*/