]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/contrib/configuration.cc
Bug #807012 also involves package dependencies :/.
[apt.git] / apt-pkg / contrib / configuration.cc
index fbe180f8ea03cfa620a5d0105aaaf99d48df303f..9007bf9ec36a2f96139417ea5ceb4404801455cc 100644 (file)
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+
 #include <algorithm>
 #include <string>
+#include <stack>
 #include <vector>
 #include <fstream>
 
@@ -223,15 +225,7 @@ string Configuration::FindFile(const char *Name,const char *Default) const
       }
       result.append(val);
    }
-
-   // do some normalisation by removing // and /./ from the path
-   size_t found = string::npos;
-   while ((found = result.find("/./")) != string::npos)
-      result.replace(found, 3, "/");
-   while ((found = result.find("//")) != string::npos)
-      result.replace(found, 2, "/");
-
-   return result;
+   return flNormalize(result);
 }
                                                                        /*}}}*/
 // Configuration::FindDir - Find a directory name                      /*{{{*/
@@ -253,12 +247,7 @@ string Configuration::FindDir(const char *Name,const char *Default) const
 // Configuration::FindVector - Find a vector of values                 /*{{{*/
 // ---------------------------------------------------------------------
 /* Returns a vector of config values under the given item */
-#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR < 13)
-vector<string> Configuration::FindVector(const char *Name) const { 
-   return FindVector(Name, ""); 
-}
-#endif
-vector<string> Configuration::FindVector(const char *Name, std::string const &Default) const
+vector<string> Configuration::FindVector(const char *Name, std::string const &Default, bool const Keys) const
 {
    vector<string> Vec;
    const Item *Top = Lookup(Name);
@@ -271,7 +260,7 @@ vector<string> Configuration::FindVector(const char *Name, std::string const &De
    Item *I = Top->Child;
    while(I != NULL)
    {
-      Vec.push_back(I->Value);
+      Vec.push_back(Keys ? I->Tag : I->Value);
       I = I->Next;
    }
    if (Vec.empty() == true)
@@ -490,6 +479,59 @@ void Configuration::Clear(string const &Name)
    }
 }
                                                                        /*}}}*/
+void Configuration::MoveSubTree(char const * const OldRootName, char const * const NewRootName)/*{{{*/
+{
+   // prevent NewRoot being a subtree of OldRoot
+   if (OldRootName == nullptr)
+      return;
+   if (NewRootName != nullptr)
+   {
+      if (strcmp(OldRootName, NewRootName) == 0)
+        return;
+      std::string const oldroot = std::string(OldRootName) + "::";
+      if (strcasestr(NewRootName, oldroot.c_str()) != NULL)
+        return;
+   }
+
+   Item * Top;
+   Item const * const OldRoot = Top = Lookup(OldRootName, false);
+   if (Top == nullptr)
+      return;
+   std::string NewRoot;
+   if (NewRootName != nullptr)
+      NewRoot.append(NewRootName).append("::");
+
+   Top->Value.clear();
+   Item * const Stop = Top;
+   Top = Top->Child;
+   Stop->Child = 0;
+   for (; Top != 0;)
+   {
+      if (Top->Child != 0)
+      {
+        Top = Top->Child;
+        continue;
+      }
+
+      while (Top != 0 && Top->Next == 0)
+      {
+        Set(NewRoot + Top->FullTag(OldRoot), Top->Value);
+        Item const * const Tmp = Top;
+        Top = Top->Parent;
+        delete Tmp;
+
+        if (Top == Stop)
+           return;
+      }
+
+      Set(NewRoot + Top->FullTag(OldRoot), Top->Value);
+      Item const * const Tmp = Top;
+      if (Top != 0)
+        Top = Top->Next;
+      delete Tmp;
+   }
+}
+                                                                       /*}}}*/
 // Configuration::Exists - Returns true if the Name exists             /*{{{*/
 // ---------------------------------------------------------------------
 /* */
@@ -626,21 +668,30 @@ 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.*/
+static void leaveCurrentScope(std::stack<std::string> &Stack, std::string &ParentTag)
+{
+   if (Stack.empty())
+      ParentTag.clear();
+   else
+   {
+      ParentTag = Stack.top();
+      Stack.pop();
+   }
+}
 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); 
-   if (!F != 0)
+   ifstream F(FName.c_str(),ios::in);
+   if (F.fail() == true)
       return _error->Errno("ifstream::ifstream",_("Opening configuration file %s"),FName.c_str());
 
    string LineBuffer;
-   string Stack[100];
-   unsigned int StackPos = 0;
-   
+   std::stack<std::string> Stack;
+
    // Parser state
    string ParentTag;
-   
+
    int CurLine = 0;
    bool InComment = false;
    while (F.eof() == false)
@@ -705,12 +756,12 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool const &AsSectio
               Start = I + 2;
               InComment = false;
               break;
-           }       
+           }
         }
         if (InComment == true)
            continue;
       }
-      
+
       // Discard single line comments
       bool InQuote = false;
       for (std::string::const_iterator I = Start;
@@ -755,9 +806,9 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool const &AsSectio
                  I = J + 1;
                  InComment = false;
                  break;
-              }               
+              }
            }
-           
+
            if (InComment == true)
              break;
         }
@@ -768,7 +819,7 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool const &AsSectio
       // Skip blank lines.
       if (Fragment.empty())
         continue;
-      
+
       // The line has actual content; interpret what it means.
       InQuote = false;
       Start = Fragment.begin();
@@ -778,7 +829,7 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool const &AsSectio
       {
         if (*I == '"')
            InQuote = !InQuote;
-        
+
         if (InQuote == false && (*I == '{' || *I == ';' || *I == '}'))
         {
            // Put the last fragment into the buffer
@@ -797,24 +848,19 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool const &AsSectio
            // brace or a semicolon)
            char TermChar = *I;
            Start = I + 1;
-           
+
            // Syntax Error
            if (TermChar == '{' && LineBuffer.empty() == true)
               return _error->Error(_("Syntax error %s:%u: Block starts with no name."),FName.c_str(),CurLine);
-           
+
            // No string on this line
            if (LineBuffer.empty() == true)
            {
               if (TermChar == '}')
-              {
-                 if (StackPos == 0)
-                    ParentTag = string();
-                 else
-                    ParentTag = Stack[--StackPos];
-              }
+                 leaveCurrentScope(Stack, ParentTag);
               continue;
            }
-           
+
            // Parse off the tag
            string Tag;
            const char *Pos = LineBuffer.c_str();
@@ -841,25 +887,23 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool const &AsSectio
            // Go down a level
            if (TermChar == '{')
            {
-              if (StackPos < sizeof(Stack)/sizeof(std::string))
-                 Stack[StackPos++] = ParentTag;
-              
+              Stack.push(ParentTag);
+
               /* Make sectional tags incorperate the section into the
                  tag string */
               if (AsSectional == true && Word.empty() == false)
               {
-                 Tag += "::" ;
-                 Tag += Word;
-                 Word = "";
+                 Tag.append("::").append(Word);
+                 Word.clear();
               }
-              
+
               if (ParentTag.empty() == true)
                  ParentTag = Tag;
               else
-                 ParentTag += string("::") + Tag;
-              Tag = string();
+                 ParentTag.append("::").append(Tag);
+              Tag.clear();
            }
-           
+
            // Generate the item name
            string Item;
            if (ParentTag.empty() == true)
@@ -871,7 +915,7 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool const &AsSectio
               else
                  Item = ParentTag;
            }
-           
+
            // Specials
            if (Tag.length() >= 1 && Tag[0] == '#')
            {
@@ -893,7 +937,7 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool const &AsSectio
                  {
                     if (ReadConfigFile(Conf,Word,AsSectional,Depth+1) == false)
                        return _error->Error(_("Syntax error %s:%u: Included from here"),FName.c_str(),CurLine);
-                 }               
+                 }
               }
               else
                  return _error->Error(_("Syntax error %s:%u: Unsupported directive '%s'"),FName.c_str(),CurLine,Tag.c_str());
@@ -906,19 +950,13 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool const &AsSectio
               if (NoWord == false)
                  Conf.Set(Item,Word);
            }
-           
+
            // Empty the buffer
            LineBuffer.clear();
-           
+
            // Move up a tag, but only if there is no bit to parse
            if (TermChar == '}')
-           {
-              if (StackPos == 0)
-                 ParentTag.clear();
-              else
-                 ParentTag = Stack[--StackPos];
-           }
-           
+              leaveCurrentScope(Stack, ParentTag);
         }
       }