#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+
#include <algorithm>
#include <string>
+#include <stack>
#include <vector>
#include <fstream>
}
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 /*{{{*/
// Configuration::FindVector - Find a vector of values /*{{{*/
// ---------------------------------------------------------------------
/* Returns a vector of config values under the given item */
-#if APT_PKG_ABI < 413
-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);
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)
}
}
/*}}}*/
+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 /*{{{*/
// ---------------------------------------------------------------------
/* */
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)
{
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;
Start = I + 2;
InComment = false;
break;
- }
+ }
}
if (InComment == true)
continue;
}
-
+
// Discard single line comments
bool InQuote = false;
for (std::string::const_iterator I = Start;
I = J + 1;
InComment = false;
break;
- }
+ }
}
-
+
if (InComment == true)
break;
}
// Skip blank lines.
if (Fragment.empty())
continue;
-
+
// The line has actual content; interpret what it means.
InQuote = false;
Start = Fragment.begin();
{
if (*I == '"')
InQuote = !InQuote;
-
+
if (InQuote == false && (*I == '{' || *I == ';' || *I == '}'))
{
// Put the last fragment into the buffer
// 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();
// 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)
else
Item = ParentTag;
}
-
+
// Specials
if (Tag.length() >= 1 && Tag[0] == '#')
{
{
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());
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);
}
}