// -*- 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;
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 */
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;
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)
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 /*{{{*/
// ---------------------------------------------------------------------
/* */
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 /*{{{*/
// ---------------------------------------------------------------------
/* */
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;
+}
+ /*}}}*/