]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/contrib/configuration.cc
More MD5
[apt.git] / apt-pkg / contrib / configuration.cc
index 433b9224446d48a7e629bcafeb3f4c00cb50750e..1c58b9881e6bea81bf24e8d067dc618edf2e8fc7 100644 (file)
@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description                                                         /*{{{*/
-// $Id: configuration.cc,v 1.6 1998/10/02 04:39:49 jgg Exp $
+// $Id: configuration.cc,v 1.13 1999/07/02 23:17:00 jgg Exp $
 /* ######################################################################
 
    Configuration Class
@@ -17,7 +17,7 @@
 #endif
 #include <apt-pkg/configuration.h>
 #include <apt-pkg/error.h>
-#include <strutl.h>
+#include <apt-pkg/strutl.h>
 
 #include <stdio.h>
 #include <fstream.h>
@@ -33,7 +33,7 @@ Configuration::Configuration()
    Root = new Item;
 }
                                                                        /*}}}*/
-// Configuration::Lookup - Lookup a single item                                                                        /*{{{*/
+// Configuration::Lookup - Lookup a single item                                /*{{{*/
 // ---------------------------------------------------------------------
 /* This will lookup a single item by name below another item. It is a 
    helper function for the main lookup function */
@@ -43,10 +43,17 @@ Configuration::Item *Configuration::Lookup(Item *Head,const char *S,
    int Res = 1;
    Item *I = Head->Child;
    Item **Last = &Head->Child;
-   for (; I != 0; Last = &I->Next, I = I->Next)
-      if ((Res = stringcasecmp(I->Tag.begin(),I->Tag.end(),S,S + Len)) == 0)
-        break;
    
+   // Empty strings match nothing. They are used for lists.
+   if (Len != 0)
+   {
+      for (; I != 0; Last = &I->Next, I = I->Next)
+        if ((Res = stringcasecmp(I->Tag.begin(),I->Tag.end(),S,S + Len)) == 0)
+           break;
+   }
+   else
+      for (; I != 0; Last = &I->Next, I = I->Next);
+      
    if (Res == 0)
       return I;
    if (Create == false)
@@ -66,11 +73,14 @@ Configuration::Item *Configuration::Lookup(Item *Head,const char *S,
    new items */
 Configuration::Item *Configuration::Lookup(const char *Name,bool Create)
 {
+   if (Name == 0)
+      return Root->Child;
+   
    const char *Start = Name;
    const char *End = Start + strlen(Name);
    const char *TagEnd = Name;
    Item *Itm = Root;
-   for (; End - TagEnd > 2; TagEnd++)
+   for (; End - TagEnd >= 2; TagEnd++)
    {
       if (TagEnd[0] == ':' && TagEnd[1] == ':')
       {
@@ -81,6 +91,13 @@ Configuration::Item *Configuration::Lookup(const char *Name,bool Create)
       }
    }   
 
+   // This must be a trailing ::, we create unique items in a list
+   if (End - Start == 0)
+   {
+      if (Create == false)
+        return 0;
+   }
+   
    Itm = Lookup(Itm,Start,End - Start,Create);
    return Itm;
 }
@@ -102,12 +119,12 @@ string Configuration::Find(const char *Name,const char *Default)
    return Itm->Value;
 }
                                                                        /*}}}*/
-// Configuration::FindDir - Find a directory                           /*{{{*/
+// Configuration::FindFile - Find a Filename                           /*{{{*/
 // ---------------------------------------------------------------------
 /* Directories are stored as the base dir in the Parent node and the
-   sub directory in sub nodes
+   sub directory in sub nodes with the final node being the end filename
  */
-string Configuration::FindDir(const char *Name,const char *Default = 0)
+string Configuration::FindFile(const char *Name,const char *Default)
 {
    Item *Itm = Lookup(Name,false);
    if (Itm == 0 || Itm->Value.empty() == true)
@@ -134,6 +151,17 @@ string Configuration::FindDir(const char *Name,const char *Default = 0)
       return Itm->Parent->Value + '/' + Itm->Value;
 }
                                                                        /*}}}*/
+// Configuration::FindDir - Find a directory name                      /*{{{*/
+// ---------------------------------------------------------------------
+/* This is like findfile execept the result is terminated in a / */
+string Configuration::FindDir(const char *Name,const char *Default)
+{
+   string Res = FindFile(Name,Default);
+   if (Res.end()[-1] != '/')
+      return Res + '/';
+   return Res;
+}
+                                                                       /*}}}*/
 // Configuration::FindI - Find an integer value                                /*{{{*/
 // ---------------------------------------------------------------------
 /* */
@@ -160,28 +188,7 @@ bool Configuration::FindB(const char *Name,bool Default)
    if (Itm == 0 || Itm->Value.empty() == true)
       return Default;
    
-   char *End;
-   int Res = strtol(Itm->Value.c_str(),&End,0);
-   if (End == Itm->Value.c_str() || Res < 0 || Res > 1)
-   {
-      // Check for positives
-      if (strcasecmp(Itm->Value.c_str(),"no") == 0 ||
-         strcasecmp(Itm->Value.c_str(),"false") == 0 ||
-         strcasecmp(Itm->Value.c_str(),"without") == 0 ||
-         strcasecmp(Itm->Value.c_str(),"disable") == 0)
-        return false;
-      
-      // Check for negatives
-      if (strcasecmp(Itm->Value.c_str(),"yes") == 0 ||
-         strcasecmp(Itm->Value.c_str(),"true") == 0 ||
-         strcasecmp(Itm->Value.c_str(),"with") == 0 ||
-         strcasecmp(Itm->Value.c_str(),"enable") == 0)
-        return true;
-      
-      return Default;
-   }
-   
-   return Res;
+   return StringToBool(Itm->Value,Default);
 }
                                                                        /*}}}*/
 // Configuration::Set - Set a value                                    /*{{{*/
@@ -219,6 +226,42 @@ bool Configuration::Exists(const char *Name)
    return true;
 }
                                                                        /*}}}*/
+// Configuration::Dump - Dump the config                               /*{{{*/
+// ---------------------------------------------------------------------
+/* Dump the entire configuration space */
+void Configuration::Dump()
+{
+   /* Write out all of the configuration directives by walking the 
+      configuration tree */
+   const Configuration::Item *Top = _config->Tree(0);
+   for (; Top != 0;)
+   {
+      clog << Top->FullTag() << " \"" << Top->Value << "\";" << endl;
+      
+      if (Top->Child != 0)
+      {
+        Top = Top->Child;
+        continue;
+      }
+      
+      while (Top != 0 && Top->Next == 0)
+        Top = Top->Parent;
+      if (Top != 0)
+        Top = Top->Next;
+   }   
+}
+                                                                       /*}}}*/
+
+// Configuration::Item::FullTag - Return the fully scoped tag          /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+string Configuration::Item::FullTag() const
+{
+   if (Parent == 0 || Parent->Parent == 0)
+      return Tag;
+   return Parent->FullTag() + "::" + Tag;
+}
+                                                                       /*}}}*/
 
 // ReadConfigFile - Read a configuration file                          /*{{{*/
 // ---------------------------------------------------------------------
@@ -233,6 +276,8 @@ bool ReadConfigFile(Configuration &Conf,string FName)
    
    char Buffer[300];
    string LineBuffer;
+   string Stack[100];
+   unsigned int StackPos = 0;
    
    // Parser state
    string ParentTag;
@@ -263,8 +308,14 @@ bool ReadConfigFile(Configuration &Conf,string FName)
       }
       
       // Discard single line comments
+      bool InQuote = false;
       for (char *I = Buffer; *I != 0; I++)
       {
+        if (*I == '"')
+           InQuote = !InQuote;
+        if (InQuote == true)
+           continue;
+        
         if (*I == '/' && I[1] == '/')
          {
            *I = 0;
@@ -275,6 +326,11 @@ bool ReadConfigFile(Configuration &Conf,string FName)
       // Look for multi line comments
       for (char *I = Buffer; *I != 0; I++)
       {
+        if (*I == '"')
+           InQuote = !InQuote;
+        if (InQuote == true)
+           continue;
+        
         if (*I == '/' && I[1] == '*')
          {
            InComment = true;
@@ -322,11 +378,10 @@ bool ReadConfigFile(Configuration &Conf,string FName)
            // Move up a tag
            if (TermChar == '}')
            {
-              string::size_type Pos = ParentTag.rfind("::");
-              if (Pos == string::npos)
+              if (StackPos == 0)
                  ParentTag = string();
               else
-                 ParentTag = string(ParentTag,0,Pos);
+                 ParentTag = Stack[--StackPos];
            }
            
            // Syntax Error
@@ -337,20 +392,16 @@ bool ReadConfigFile(Configuration &Conf,string FName)
               continue;
 
            // Parse off the tag
-           string::size_type Pos = LineBuffer.find(' ');
-           if (Pos == string::npos)
-           {
-              if (TermChar == '{')
-                 Pos = LineBuffer.length();
-              else
-                 return _error->Error("Syntax error %s:%u: Tag with no value",FName.c_str(),CurLine);
-           }
+           string Tag;
+           const char *Pos = LineBuffer.c_str();
+           if (ParseQuoteWord(Pos,Tag) == false)
+              return _error->Error("Syntax error %s:%u: Malformed Tag",FName.c_str(),CurLine);     
            
-           string Tag = string(LineBuffer,0,Pos);
-
            // Go down a level
            if (TermChar == '{')
            {
+              if (StackPos <= 100)
+                 Stack[StackPos++] = ParentTag;
               if (ParentTag.empty() == true)
                  ParentTag = Tag;
               else
@@ -358,28 +409,27 @@ bool ReadConfigFile(Configuration &Conf,string FName)
               Tag = string();
            }
 
-           // We dont have a value to set
-           if (Pos == LineBuffer.length())
+           // Parse off the word
+           string Word;
+           if (ParseCWord(Pos,Word) == false)
            {
-              LineBuffer = string();
-              continue;
+              if (TermChar != '{')
+              {
+                 Word = Tag;
+                 Tag = "";
+              }               
            }
            
-           // Parse off the word
-           string Word;
-           if (ParseCWord(LineBuffer.c_str()+Pos,Word) == false)
-              return _error->Error("Syntax error %s:%u: Malformed value",FName.c_str(),CurLine);
-              
            // Generate the item name
            string Item;
            if (ParentTag.empty() == true)
               Item = Tag;
            else
            {
-              if (Tag.empty() == true)
-                 Item = ParentTag;
-              else
+              if (TermChar != '{' || Tag.empty() == false)
                  Item = ParentTag + "::" + Tag;
+              else
+                 Item = ParentTag;
            }
            
            // Set the item in the configuration class