// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: configuration.cc,v 1.4 1998/09/22 05:30:26 jgg Exp $
+// $Id: configuration.cc,v 1.13 1999/07/02 23:17:00 jgg Exp $
/* ######################################################################
Configuration Class
#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>
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 */
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)
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] == ':')
{
}
}
+ // 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;
}
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 /*{{{*/
// ---------------------------------------------------------------------
/* */
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,"no") == 0 ||
- strcasecmp(Itm->Value,"false") == 0 ||
- strcasecmp(Itm->Value,"without") == 0 ||
- strcasecmp(Itm->Value,"disable") == 0)
- return false;
-
- // Check for negatives
- if (strcasecmp(Itm->Value,"no") == 0 ||
- strcasecmp(Itm->Value,"false") == 0 ||
- strcasecmp(Itm->Value,"without") == 0 ||
- strcasecmp(Itm->Value,"disable") == 0)
- return false;
-
- return Default;
- }
-
- return Res;
+ return StringToBool(Itm->Value,Default);
}
/*}}}*/
// Configuration::Set - Set a value /*{{{*/
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 /*{{{*/
// ---------------------------------------------------------------------
char Buffer[300];
string LineBuffer;
+ string Stack[100];
+ unsigned int StackPos = 0;
// Parser state
string ParentTag;
}
// 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;
// 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;
// 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
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
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