X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/d0f1646ae06ca5710b015662b9244e277dce73fa..769e06cf07625f4a2f5c84340ef6af697d7b0894:/apt-pkg/contrib/configuration.cc diff --git a/apt-pkg/contrib/configuration.cc b/apt-pkg/contrib/configuration.cc index ece05e8f6..9007bf9ec 100644 --- a/apt-pkg/contrib/configuration.cc +++ b/apt-pkg/contrib/configuration.cc @@ -15,15 +15,28 @@ ##################################################################### */ /*}}}*/ // Include files /*{{{*/ +#include + #include #include #include #include -#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include -#include + +#include using namespace std; /*}}}*/ @@ -39,8 +52,7 @@ Configuration::Configuration() : ToFree(true) } Configuration::Configuration(const Item *Root) : Root((Item *)Root), ToFree(false) { -}; - +} /*}}}*/ // Configuration::~Configuration - Destructor /*{{{*/ // --------------------------------------------------------------------- @@ -168,42 +180,52 @@ string Configuration::Find(const char *Name,const char *Default) const string Configuration::FindFile(const char *Name,const char *Default) const { const Item *RootItem = Lookup("RootDir"); - std::string rootDir = (RootItem == 0) ? "" : RootItem->Value; - if(rootDir.size() > 0 && rootDir[rootDir.size() - 1] != '/') - rootDir.push_back('/'); + std::string result = (RootItem == 0) ? "" : RootItem->Value; + if(result.empty() == false && result[result.size() - 1] != '/') + result.push_back('/'); const Item *Itm = Lookup(Name); if (Itm == 0 || Itm->Value.empty() == true) { - if (Default == 0) - return rootDir; - else - return rootDir + Default; + if (Default != 0) + result.append(Default); } - - string val = Itm->Value; - while (Itm->Parent != 0 && Itm->Parent->Value.empty() == false) - { - // Absolute - if (val.length() >= 1 && val[0] == '/') - break; - - // ~/foo or ./foo - if (val.length() >= 2 && (val[0] == '~' || val[0] == '.') && val[1] == '/') - break; - - // ../foo - if (val.length() >= 3 && val[0] == '.' && val[1] == '.' && val[2] == '/') - break; - - if (Itm->Parent->Value.end()[-1] != '/') - val.insert(0, "/"); + else + { + string val = Itm->Value; + while (Itm->Parent != 0) + { + if (Itm->Parent->Value.empty() == true) + { + Itm = Itm->Parent; + continue; + } - val.insert(0, Itm->Parent->Value); - Itm = Itm->Parent; - } + // Absolute + if (val.length() >= 1 && val[0] == '/') + { + if (val.compare(0, 9, "/dev/null") == 0) + val.erase(9); + break; + } + + // ~/foo or ./foo + if (val.length() >= 2 && (val[0] == '~' || val[0] == '.') && val[1] == '/') + break; + + // ../foo + if (val.length() >= 3 && val[0] == '.' && val[1] == '.' && val[2] == '/') + break; + + if (Itm->Parent->Value.end()[-1] != '/') + val.insert(0, "/"); - return rootDir + val; + val.insert(0, Itm->Parent->Value); + Itm = Itm->Parent; + } + result.append(val); + } + return flNormalize(result); } /*}}}*/ // Configuration::FindDir - Find a directory name /*{{{*/ @@ -213,26 +235,37 @@ string Configuration::FindDir(const char *Name,const char *Default) const { string Res = FindFile(Name,Default); if (Res.end()[-1] != '/') + { + size_t const found = Res.rfind("/dev/null"); + if (found != string::npos && found == Res.size() - 9) + return Res; // /dev/null returning return Res + '/'; + } return Res; } /*}}}*/ // Configuration::FindVector - Find a vector of values /*{{{*/ // --------------------------------------------------------------------- /* Returns a vector of config values under the given item */ -vector Configuration::FindVector(const char *Name) const +vector Configuration::FindVector(const char *Name, std::string const &Default, bool const Keys) const { vector Vec; const Item *Top = Lookup(Name); if (Top == NULL) - return Vec; + return VectorizeString(Default, ','); + + if (Top->Value.empty() == false) + return VectorizeString(Top->Value, ','); 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) + return VectorizeString(Default, ','); + return Vec; } /*}}}*/ @@ -394,6 +427,18 @@ void Configuration::Clear(string const &Name, string const &Value) } } +} + /*}}}*/ +// Configuration::Clear - Clear everything /*{{{*/ +// --------------------------------------------------------------------- +void Configuration::Clear() +{ + const Configuration::Item *Top = Tree(0); + while( Top != 0 ) + { + Clear(Top->FullTag()); + Top = Top->Next; + } } /*}}}*/ // Configuration::Clear - Clear an entire tree /*{{{*/ @@ -434,6 +479,59 @@ void Configuration::Clear(string const &Name) } } /*}}}*/ +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 /*{{{*/ // --------------------------------------------------------------------- /* */ @@ -473,24 +571,80 @@ bool Configuration::ExistsAny(const char *Name) const /* Dump the entire configuration space */ void Configuration::Dump(ostream& str) { - /* Write out all of the configuration directives by walking the + Dump(str, NULL, "%f \"%v\";\n", true); +} +void Configuration::Dump(ostream& str, char const * const root, + char const * const formatstr, bool const emptyValue) +{ + const Configuration::Item* Top = Tree(root); + if (Top == 0) + return; + const Configuration::Item* const Root = (root == NULL) ? NULL : Top; + std::vector const format = VectorizeString(formatstr, '%'); + + /* Write out all of the configuration directives by walking the configuration tree */ - const Configuration::Item *Top = Tree(0); - for (; Top != 0;) - { - str << Top->FullTag() << " \"" << Top->Value << "\";" << endl; - + do { + if (emptyValue == true || Top->Value.empty() == emptyValue) + { + std::vector::const_iterator f = format.begin(); + str << *f; + for (++f; f != format.end(); ++f) + { + if (f->empty() == true) + { + ++f; + str << '%' << *f; + continue; + } + char const type = (*f)[0]; + if (type == 'f') + str << Top->FullTag(); + else if (type == 't') + str << Top->Tag; + else if (type == 'v') + str << Top->Value; + else if (type == 'F') + str << QuoteString(Top->FullTag(), "=\"\n"); + else if (type == 'T') + str << QuoteString(Top->Tag, "=\"\n"); + else if (type == 'V') + str << QuoteString(Top->Value, "=\"\n"); + else if (type == 'n') + str << "\n"; + else if (type == 'N') + str << "\t"; + else + str << '%' << type; + str << f->c_str() + 1; + } + } + if (Top->Child != 0) { Top = Top->Child; continue; } - + while (Top != 0 && Top->Next == 0) Top = Top->Parent; if (Top != 0) Top = Top->Next; - } + + if (Root != NULL) + { + const Configuration::Item* I = Top; + while(I != 0) + { + if (I == Root) + break; + else + I = I->Parent; + } + if (I == 0) + break; + } + } while (Top != 0); } /*}}}*/ @@ -514,21 +668,30 @@ string Configuration::Item::FullTag(const Item *Stop) const 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 &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) -{ +{ // Open the stream for reading - ifstream F(FName.c_str(),ios::in); - if (!F != 0) + ifstream F(FName.c_str(),ios::in); + if (F.fail() == true) return _error->Errno("ifstream::ifstream",_("Opening configuration file %s"),FName.c_str()); string LineBuffer; - string Stack[100]; - unsigned int StackPos = 0; - + std::stack Stack; + // Parser state string ParentTag; - + int CurLine = 0; bool InComment = false; while (F.eof() == false) @@ -593,12 +756,12 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool const &AsSectio Start = I + 2; InComment = false; break; - } + } } if (InComment == true) continue; } - + // Discard single line comments bool InQuote = false; for (std::string::const_iterator I = Start; @@ -643,9 +806,9 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool const &AsSectio I = J + 1; InComment = false; break; - } + } } - + if (InComment == true) break; } @@ -656,7 +819,7 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool const &AsSectio // Skip blank lines. if (Fragment.empty()) continue; - + // The line has actual content; interpret what it means. InQuote = false; Start = Fragment.begin(); @@ -666,7 +829,7 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool const &AsSectio { if (*I == '"') InQuote = !InQuote; - + if (InQuote == false && (*I == '{' || *I == ';' || *I == '}')) { // Put the last fragment into the buffer @@ -685,24 +848,19 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool const &AsSectio // 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(); @@ -729,25 +887,23 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool const &AsSectio // Go down a level if (TermChar == '{') { - if (StackPos <= 100) - 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) @@ -759,7 +915,7 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool const &AsSectio else Item = ParentTag; } - + // Specials if (Tag.length() >= 1 && Tag[0] == '#') { @@ -781,7 +937,7 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool const &AsSectio { 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()); @@ -794,19 +950,13 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool const &AsSectio 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); } } @@ -870,13 +1020,13 @@ Configuration::MatchAgainstConfig::MatchAgainstConfig(char const * Config) { regfree(p); delete p; - clearPatterns(); - _error->Warning("Regex compilation error for '%s' in configuration option '%s'", - s->c_str(), Config); - return; + _error->Warning("Invalid regular expression '%s' in configuration " + "option '%s' will be ignored.", + s->c_str(), Config); + continue; } } - if (strings.size() == 0) + if (strings.empty() == true) patterns.push_back(NULL); } /*}}}*/ @@ -894,6 +1044,7 @@ void Configuration::MatchAgainstConfig::clearPatterns() regfree(*p); delete *p; } + patterns.clear(); } /*}}}*/ // MatchAgainstConfig::Match - returns true if a pattern matches /*{{{*/