Working acquire code
[ntk/apt.git] / apt-pkg / contrib / configuration.cc
index 72b654b..da026f0 100644 (file)
@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description                                                         /*{{{*/
-// $Id: configuration.cc,v 1.3 1998/07/12 23:58:44 jgg Exp $
+// $Id: configuration.cc,v 1.10 1998/11/05 07:21:43 jgg Exp $
 /* ######################################################################
 
    Configuration Class
 #pragma implementation "apt-pkg/configuration.h"
 #endif
 #include <apt-pkg/configuration.h>
+#include <apt-pkg/error.h>
 #include <strutl.h>
 
 #include <stdio.h>
+#include <fstream.h>
                                                                        /*}}}*/
 
 Configuration *_config = new Configuration;
@@ -31,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 */
@@ -64,6 +66,9 @@ 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;
@@ -100,11 +105,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 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)
@@ -115,14 +121,33 @@ string Configuration::FindDir(const char *Name,const char *Default = 0)
         return Default;
    }
    
+   // Absolute path
    if (Itm->Value[0] == '/' || Itm->Parent == 0)
       return Itm->Value;
+   
+   // ./ is also considered absolute as is anything with ~ in it
+   if (Itm->Value[0] != 0 && 
+       ((Itm->Value[0] == '.' && Itm->Value[1] == '/') ||
+       (Itm->Value[0] == '~' && Itm->Value[1] == '/')))
+      return Itm->Value;
+   
    if (Itm->Parent->Value.end()[-1] == '/')
       return Itm->Parent->Value + Itm->Value;
    else
       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                                /*{{{*/
 // ---------------------------------------------------------------------
 /* */
@@ -140,6 +165,18 @@ int Configuration::FindI(const char *Name,int Default)
    return Res;
 }
                                                                        /*}}}*/
+// Configuration::FindB - Find a boolean type                          /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool Configuration::FindB(const char *Name,bool Default)
+{
+   Item *Itm = Lookup(Name,false);
+   if (Itm == 0 || Itm->Value.empty() == true)
+      return Default;
+   
+   return StringToBool(Itm->Value,Default);
+}
+                                                                       /*}}}*/
 // Configuration::Set - Set a value                                    /*{{{*/
 // ---------------------------------------------------------------------
 /* */
@@ -164,3 +201,244 @@ void Configuration::Set(const char *Name,int Value)
    Itm->Value = S;
 }
                                                                        /*}}}*/
+// Configuration::Exists - Returns true if the Name exists             /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool Configuration::Exists(const char *Name)
+{
+   Item *Itm = Lookup(Name,false);
+   if (Itm == 0)
+      return false;
+   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                          /*{{{*/
+// ---------------------------------------------------------------------
+/* The configuration format is very much like the named.conf format
+   used in bind8, in fact this routine can parse most named.conf files. */
+bool ReadConfigFile(Configuration &Conf,string FName)
+{
+   // Open the stream for reading
+   ifstream F(FName.c_str(),ios::in | ios::nocreate);
+   if (!F != 0)
+      return _error->Errno("ifstream::ifstream","Opening configuration file %s",FName.c_str());
+   
+   char Buffer[300];
+   string LineBuffer;
+   
+   // Parser state
+   string ParentTag;
+   
+   int CurLine = 0;
+   bool InComment = false;
+   while (F.eof() == false)
+   {
+      F.getline(Buffer,sizeof(Buffer));
+      CurLine++;
+      _strtabexpand(Buffer,sizeof(Buffer));
+      _strstrip(Buffer);
+
+      // Multi line comment
+      if (InComment == true)
+      {
+        for (const char *I = Buffer; *I != 0; I++)
+        {
+           if (*I == '*' && I[1] == '/')
+           {
+              memmove(Buffer,I+2,strlen(I+2) + 1);
+              InComment = false;
+              break;
+           }       
+        }
+        if (InComment == true)
+           continue;
+      }
+      
+      // 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;
+           break;
+        }
+      }
+      
+      // 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;
+           for (char *J = Buffer; *J != 0; J++)
+           {
+              if (*J == '*' && J[1] == '/')
+              {
+                 memmove(I,J+2,strlen(J+2) + 1);
+                 InComment = false;
+                 break;
+              }               
+           }
+           
+           if (InComment == true)
+           {
+              *I = 0;
+              break;
+           }       
+        }
+      }
+      
+      // Blank
+      if (Buffer[0] == 0)
+        continue;
+      
+      // We now have a valid line fragment
+      for (char *I = Buffer; *I != 0;)
+      {
+        if (*I == '{' || *I == ';' || *I == '}')
+        {
+           // Put the last fragement into the buffer
+           char *Start = Buffer;
+           char *Stop = I;
+           for (; Start != I && isspace(*Start) != 0; Start++);
+           for (; Stop != Start && isspace(Stop[-1]) != 0; Stop--);
+           if (LineBuffer.empty() == false && Stop - Start != 0)
+              LineBuffer += ' ';
+           LineBuffer += string(Start,Stop - Start);
+           
+           // Remove the fragment
+           char TermChar = *I;
+           memmove(Buffer,I + 1,strlen(I + 1) + 1);
+           I = Buffer;
+
+           // Move up a tag
+           if (TermChar == '}')
+           {
+              string::size_type Pos = ParentTag.rfind("::");
+              if (Pos == string::npos)
+                 ParentTag = string();
+              else
+                 ParentTag = string(ParentTag,0,Pos);
+           }
+           
+           // Syntax Error
+           if (TermChar == '{' && LineBuffer.empty() == true)
+              return _error->Error("Syntax error %s:%u: Block starts with no name.",FName.c_str(),CurLine);
+           
+           if (LineBuffer.empty() == true)
+              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 = string(LineBuffer,0,Pos);
+
+           // Go down a level
+           if (TermChar == '{')
+           {
+              if (ParentTag.empty() == true)
+                 ParentTag = Tag;
+              else
+                 ParentTag += string("::") + Tag;
+              Tag = string();
+           }
+
+           // We dont have a value to set
+           if (Pos == LineBuffer.length())
+           {
+              LineBuffer = string();
+              continue;
+           }
+           
+           // 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
+                 Item = ParentTag + "::" + Tag;
+           }
+           
+           // Set the item in the configuration class
+           Conf.Set(Item,Word);
+                           
+           // Empty the buffer
+           LineBuffer = string();
+        }
+        else
+           I++;
+      }
+
+      // Store the fragment
+      const char *Stripd = _strstrip(Buffer);
+      if (*Stripd != 0 && LineBuffer.empty() == false)
+        LineBuffer += " ";
+      LineBuffer += Stripd;
+   }
+   
+   return true;
+}
+                                                                       /*}}}*/