X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/b39c18596d05cea1b3c0f0445b17080e9a2e4c19..3b5607fc31371190470074371793cb8500b5139e:/apt-pkg/contrib/configuration.cc diff --git a/apt-pkg/contrib/configuration.cc b/apt-pkg/contrib/configuration.cc index 8e3b84499..00f6ad0f9 100644 --- a/apt-pkg/contrib/configuration.cc +++ b/apt-pkg/contrib/configuration.cc @@ -15,15 +15,26 @@ ##################################################################### */ /*}}}*/ // Include files /*{{{*/ +#include + #include #include #include #include -#include - +#include + +#include +#include +#include +#include +#include +#include +#include +#include #include #include -#include + +#include using namespace std; /*}}}*/ @@ -39,8 +50,7 @@ Configuration::Configuration() : ToFree(true) } Configuration::Configuration(const Item *Root) : Root((Item *)Root), ToFree(false) { -}; - +} /*}}}*/ // Configuration::~Configuration - Destructor /*{{{*/ // --------------------------------------------------------------------- @@ -79,7 +89,7 @@ Configuration::~Configuration() /* This will lookup a single item by name below another item. It is a helper function for the main lookup function */ Configuration::Item *Configuration::Lookup(Item *Head,const char *S, - unsigned long Len,bool Create) + unsigned long const &Len,bool const &Create) { int Res = 1; Item *I = Head->Child; @@ -112,7 +122,7 @@ Configuration::Item *Configuration::Lookup(Item *Head,const char *S, // --------------------------------------------------------------------- /* This performs a fully scoped lookup of a given name, possibly creating new items */ -Configuration::Item *Configuration::Lookup(const char *Name,bool Create) +Configuration::Item *Configuration::Lookup(const char *Name,bool const &Create) { if (Name == 0) return Root->Child; @@ -168,42 +178,60 @@ 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; + } + + // 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, "/"); - val.insert(0, Itm->Parent->Value); - Itm = Itm->Parent; + val.insert(0, Itm->Parent->Value); + Itm = Itm->Parent; + } + result.append(val); } - return rootDir + 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; } /*}}}*/ // Configuration::FindDir - Find a directory name /*{{{*/ @@ -213,19 +241,30 @@ 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 +#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR < 13) +vector Configuration::FindVector(const char *Name) const { return FindVector(Name, ""); } +#endif +vector Configuration::FindVector(const char *Name, std::string const &Default) 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) @@ -233,13 +272,16 @@ vector Configuration::FindVector(const char *Name) const Vec.push_back(I->Value); I = I->Next; } + if (Vec.empty() == true) + return VectorizeString(Default, ','); + return Vec; } /*}}}*/ // Configuration::FindI - Find an integer value /*{{{*/ // --------------------------------------------------------------------- /* */ -int Configuration::FindI(const char *Name,int Default) const +int Configuration::FindI(const char *Name,int const &Default) const { const Item *Itm = Lookup(Name); if (Itm == 0 || Itm->Value.empty() == true) @@ -256,7 +298,7 @@ int Configuration::FindI(const char *Name,int Default) const // Configuration::FindB - Find a boolean type /*{{{*/ // --------------------------------------------------------------------- /* */ -bool Configuration::FindB(const char *Name,bool Default) const +bool Configuration::FindB(const char *Name,bool const &Default) const { const Item *Itm = Lookup(Name); if (Itm == 0 || Itm->Value.empty() == true) @@ -318,6 +360,19 @@ void Configuration::CndSet(const char *Name,const string &Value) Itm->Value = Value; } /*}}}*/ +// Configuration::Set - Set an integer value /*{{{*/ +// --------------------------------------------------------------------- +/* */ +void Configuration::CndSet(const char *Name,int const Value) +{ + Item *Itm = Lookup(Name,true); + if (Itm == 0 || Itm->Value.empty() == false) + return; + char S[300]; + snprintf(S,sizeof(S),"%i",Value); + Itm->Value = S; +} + /*}}}*/ // Configuration::Set - Set a value /*{{{*/ // --------------------------------------------------------------------- /* */ @@ -332,7 +387,7 @@ void Configuration::Set(const char *Name,const string &Value) // Configuration::Set - Set an integer value /*{{{*/ // --------------------------------------------------------------------- /* */ -void Configuration::Set(const char *Name,int Value) +void Configuration::Set(const char *Name,int const &Value) { Item *Itm = Lookup(Name,true); if (Itm == 0) @@ -345,7 +400,7 @@ void Configuration::Set(const char *Name,int Value) // Configuration::Clear - Clear an single value from a list /*{{{*/ // --------------------------------------------------------------------- /* */ -void Configuration::Clear(const string Name, int Value) +void Configuration::Clear(string const &Name, int const &Value) { char S[300]; snprintf(S,sizeof(S),"%i",Value); @@ -355,7 +410,7 @@ void Configuration::Clear(const string Name, int Value) // Configuration::Clear - Clear an single value from a list /*{{{*/ // --------------------------------------------------------------------- /* */ -void Configuration::Clear(const string Name, string Value) +void Configuration::Clear(string const &Name, string const &Value) { Item *Top = Lookup(Name.c_str(),false); if (Top == 0 || Top->Child == 0) @@ -381,12 +436,24 @@ void Configuration::Clear(const string Name, string 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 /*{{{*/ // --------------------------------------------------------------------- /* */ -void Configuration::Clear(string Name) +void Configuration::Clear(string const &Name) { Item *Top = Lookup(Name.c_str(),false); if (Top == 0) @@ -460,24 +527,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); } /*}}}*/ @@ -501,8 +624,8 @@ 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.*/ -bool ReadConfigFile(Configuration &Conf,const string &FName,bool AsSectional, - unsigned Depth) +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); @@ -659,9 +782,9 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool AsSectional, // Put the last fragment into the buffer std::string::const_iterator NonWhitespaceStart = Start; std::string::const_iterator NonWhitespaceStop = I; - for (; NonWhitespaceStart != I && isspace(*NonWhitespaceStart) != 0; NonWhitespaceStart++) + for (; NonWhitespaceStart != I && isspace(*NonWhitespaceStart) != 0; ++NonWhitespaceStart) ; - for (; NonWhitespaceStop != NonWhitespaceStart && isspace(NonWhitespaceStop[-1]) != 0; NonWhitespaceStop--) + for (; NonWhitespaceStop != NonWhitespaceStart && isspace(NonWhitespaceStop[-1]) != 0; --NonWhitespaceStop) ; if (LineBuffer.empty() == false && NonWhitespaceStop - NonWhitespaceStart != 0) LineBuffer += ' '; @@ -716,7 +839,7 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool AsSectional, // Go down a level if (TermChar == '{') { - if (StackPos <= 100) + if (StackPos < sizeof(Stack)/sizeof(std::string)) Stack[StackPos++] = ParentTag; /* Make sectional tags incorperate the section into the @@ -773,6 +896,8 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool AsSectional, else return _error->Error(_("Syntax error %s:%u: Unsupported directive '%s'"),FName.c_str(),CurLine,Tag.c_str()); } + else if (Tag.empty() == true && NoWord == false && Word == "#clear") + return _error->Error(_("Syntax error %s:%u: clear directive requires an option tree as argument"),FName.c_str(),CurLine); else { // Set the item in the configuration class @@ -830,14 +955,66 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool AsSectional, // --------------------------------------------------------------------- /* */ bool ReadConfigDir(Configuration &Conf,const string &Dir, - bool AsSectional, unsigned Depth) + bool const &AsSectional, unsigned const &Depth) { vector const List = GetListOfFilesInDir(Dir, "conf", true, true); // Read the files - for (vector::const_iterator I = List.begin(); I != List.end(); I++) + for (vector::const_iterator I = List.begin(); I != List.end(); ++I) if (ReadConfigFile(Conf,*I,AsSectional,Depth) == false) return false; return true; } /*}}}*/ +// MatchAgainstConfig Constructor /*{{{*/ +Configuration::MatchAgainstConfig::MatchAgainstConfig(char const * Config) +{ + std::vector const strings = _config->FindVector(Config); + for (std::vector::const_iterator s = strings.begin(); + s != strings.end(); ++s) + { + regex_t *p = new regex_t; + if (regcomp(p, s->c_str(), REG_EXTENDED | REG_ICASE | REG_NOSUB) == 0) + patterns.push_back(p); + else + { + regfree(p); + delete p; + _error->Warning("Invalid regular expression '%s' in configuration " + "option '%s' will be ignored.", + s->c_str(), Config); + continue; + } + } + if (strings.empty() == true) + patterns.push_back(NULL); +} + /*}}}*/ +// MatchAgainstConfig Destructor /*{{{*/ +Configuration::MatchAgainstConfig::~MatchAgainstConfig() +{ + clearPatterns(); +} +void Configuration::MatchAgainstConfig::clearPatterns() +{ + for(std::vector::const_iterator p = patterns.begin(); + p != patterns.end(); ++p) + { + if (*p == NULL) continue; + regfree(*p); + delete *p; + } + patterns.clear(); +} + /*}}}*/ +// MatchAgainstConfig::Match - returns true if a pattern matches /*{{{*/ +bool Configuration::MatchAgainstConfig::Match(char const * str) const +{ + for(std::vector::const_iterator p = patterns.begin(); + p != patterns.end(); ++p) + if (*p != NULL && regexec(*p, str, 0, 0, 0) == 0) + return true; + + return false; +} + /*}}}*/