summaryrefslogtreecommitdiff
path: root/apt-pkg/contrib/configuration.cc
diff options
context:
space:
mode:
Diffstat (limited to 'apt-pkg/contrib/configuration.cc')
-rw-r--r--apt-pkg/contrib/configuration.cc168
1 files changed, 166 insertions, 2 deletions
diff --git a/apt-pkg/contrib/configuration.cc b/apt-pkg/contrib/configuration.cc
index 9007bf9ec..78a98d614 100644
--- a/apt-pkg/contrib/configuration.cc
+++ b/apt-pkg/contrib/configuration.cc
@@ -31,10 +31,13 @@
#include <string.h>
#include <algorithm>
+#include <iterator>
#include <string>
#include <stack>
#include <vector>
#include <fstream>
+#include <sstream>
+#include <unordered_map>
#include <apti18n.h>
@@ -43,6 +46,155 @@ using namespace std;
Configuration *_config = new Configuration;
+/* TODO: This config verification shouldn't be using a static variable
+ but a Cnf-member – but that would need ABI breaks and stuff and for now
+ that really is an apt-dev-only tool, so it isn't that bad that it is
+ unusable and allaround a bit strange */
+enum class APT_HIDDEN ConfigType { UNDEFINED, INT, BOOL, STRING, STRING_OR_BOOL, STRING_OR_LIST, FILE, DIR, LIST, PROGRAM_PATH = FILE };
+APT_HIDDEN std::unordered_map<std::string, ConfigType> apt_known_config {};
+static std::string getConfigTypeString(ConfigType const type) /*{{{*/
+{
+ switch (type)
+ {
+ case ConfigType::UNDEFINED: return "UNDEFINED";
+ case ConfigType::INT: return "INT";
+ case ConfigType::BOOL: return "BOOL";
+ case ConfigType::STRING: return "STRING";
+ case ConfigType::STRING_OR_BOOL: return "STRING_OR_BOOL";
+ case ConfigType::FILE: return "FILE";
+ case ConfigType::DIR: return "DIR";
+ case ConfigType::LIST: return "LIST";
+ case ConfigType::STRING_OR_LIST: return "STRING_OR_LIST";
+ }
+ return "UNKNOWN";
+}
+ /*}}}*/
+static ConfigType getConfigType(std::string const &type) /*{{{*/
+{
+ if (type == "<INT>")
+ return ConfigType::INT;
+ else if (type == "<BOOL>")
+ return ConfigType::BOOL;
+ else if (type == "<STRING>")
+ return ConfigType::STRING;
+ else if (type == "<STRING_OR_BOOL>")
+ return ConfigType::STRING_OR_BOOL;
+ else if (type == "<FILE>")
+ return ConfigType::FILE;
+ else if (type == "<DIR>")
+ return ConfigType::DIR;
+ else if (type == "<LIST>")
+ return ConfigType::LIST;
+ else if (type == "<STRING_OR_LIST>")
+ return ConfigType::STRING_OR_LIST;
+ else if (type == "<PROGRAM_PATH>")
+ return ConfigType::PROGRAM_PATH;
+ return ConfigType::UNDEFINED;
+}
+ /*}}}*/
+// checkFindConfigOptionType - workhorse of option checking /*{{{*/
+static void checkFindConfigOptionTypeInternal(std::string name, ConfigType const type)
+{
+ std::transform(name.begin(), name.end(), name.begin(), ::tolower);
+ auto known = apt_known_config.find(name);
+ if (known == apt_known_config.cend())
+ {
+ auto const rcolon = name.rfind(':');
+ if (rcolon != std::string::npos)
+ {
+ known = apt_known_config.find(name.substr(0, rcolon) + ":*");
+ if (known == apt_known_config.cend())
+ {
+ auto const parts = StringSplit(name, "::");
+ size_t psize = parts.size();
+ if (psize > 1)
+ {
+ for (size_t max = psize; max != 1; --max)
+ {
+ std::ostringstream os;
+ std::copy(parts.begin(), parts.begin() + max, std::ostream_iterator<std::string>(os, "::"));
+ os << "**";
+ known = apt_known_config.find(os.str());
+ if (known != apt_known_config.cend() && known->second == ConfigType::UNDEFINED)
+ return;
+ }
+ for (size_t max = psize - 1; max != 1; --max)
+ {
+ std::ostringstream os;
+ std::copy(parts.begin(), parts.begin() + max - 1, std::ostream_iterator<std::string>(os, "::"));
+ os << "*::";
+ std::copy(parts.begin() + max + 1, parts.end() - 1, std::ostream_iterator<std::string>(os, "::"));
+ os << *(parts.end() - 1);
+ known = apt_known_config.find(os.str());
+ if (known != apt_known_config.cend())
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (known == apt_known_config.cend())
+ _error->Warning("Using unknown config option »%s« of type %s",
+ name.c_str(), getConfigTypeString(type).c_str());
+ else if (known->second != type)
+ {
+ if (known->second == ConfigType::DIR && type == ConfigType::FILE)
+ ; // implementation detail
+ else if (type == ConfigType::STRING && (known->second == ConfigType::FILE || known->second == ConfigType::DIR))
+ ; // TODO: that might be an error or not, we will figure this out later
+ else if (known->second == ConfigType::STRING_OR_BOOL && (type == ConfigType::BOOL || type == ConfigType::STRING))
+ ;
+ else if (known->second == ConfigType::STRING_OR_LIST && (type == ConfigType::LIST || type == ConfigType::STRING))
+ ;
+ else
+ _error->Warning("Using config option »%s« of type %s as a type %s",
+ name.c_str(), getConfigTypeString(known->second).c_str(), getConfigTypeString(type).c_str());
+ }
+}
+static void checkFindConfigOptionType(char const * const name, ConfigType const type)
+{
+ if (apt_known_config.empty())
+ return;
+ checkFindConfigOptionTypeInternal(name, type);
+}
+ /*}}}*/
+static bool LoadConfigurationIndex(std::string const &filename) /*{{{*/
+{
+ apt_known_config.clear();
+ if (filename.empty())
+ return true;
+ Configuration Idx;
+ if (ReadConfigFile(Idx, filename) == false)
+ return false;
+
+ Configuration::Item const * Top = Idx.Tree(nullptr);
+ if (unlikely(Top == nullptr))
+ return false;
+
+ do {
+ if (Top->Value.empty() == false)
+ {
+ std::string fulltag = Top->FullTag();
+ std::transform(fulltag.begin(), fulltag.end(), fulltag.begin(), ::tolower);
+ apt_known_config.emplace(std::move(fulltag), getConfigType(Top->Value));
+ }
+
+ if (Top->Child != nullptr)
+ {
+ Top = Top->Child;
+ continue;
+ }
+
+ while (Top != nullptr && Top->Next == nullptr)
+ Top = Top->Parent;
+ if (Top != nullptr)
+ Top = Top->Next;
+ } while (Top != nullptr);
+
+ return true;
+}
+ /*}}}*/
+
// Configuration::Configuration - Constructor /*{{{*/
// ---------------------------------------------------------------------
/* */
@@ -160,6 +312,7 @@ Configuration::Item *Configuration::Lookup(const char *Name,bool const &Create)
/* */
string Configuration::Find(const char *Name,const char *Default) const
{
+ checkFindConfigOptionType(Name, ConfigType::STRING);
const Item *Itm = Lookup(Name);
if (Itm == 0 || Itm->Value.empty() == true)
{
@@ -179,6 +332,7 @@ string Configuration::Find(const char *Name,const char *Default) const
*/
string Configuration::FindFile(const char *Name,const char *Default) const
{
+ checkFindConfigOptionType(Name, ConfigType::FILE);
const Item *RootItem = Lookup("RootDir");
std::string result = (RootItem == 0) ? "" : RootItem->Value;
if(result.empty() == false && result[result.size() - 1] != '/')
@@ -233,6 +387,7 @@ string Configuration::FindFile(const char *Name,const char *Default) const
/* This is like findfile execept the result is terminated in a / */
string Configuration::FindDir(const char *Name,const char *Default) const
{
+ checkFindConfigOptionType(Name, ConfigType::DIR);
string Res = FindFile(Name,Default);
if (Res.end()[-1] != '/')
{
@@ -249,6 +404,7 @@ string Configuration::FindDir(const char *Name,const char *Default) const
/* Returns a vector of config values under the given item */
vector<string> Configuration::FindVector(const char *Name, std::string const &Default, bool const Keys) const
{
+ checkFindConfigOptionType(Name, ConfigType::LIST);
vector<string> Vec;
const Item *Top = Lookup(Name);
if (Top == NULL)
@@ -274,6 +430,7 @@ vector<string> Configuration::FindVector(const char *Name, std::string const &De
/* */
int Configuration::FindI(const char *Name,int const &Default) const
{
+ checkFindConfigOptionType(Name, ConfigType::INT);
const Item *Itm = Lookup(Name);
if (Itm == 0 || Itm->Value.empty() == true)
return Default;
@@ -291,6 +448,7 @@ int Configuration::FindI(const char *Name,int const &Default) const
/* */
bool Configuration::FindB(const char *Name,bool const &Default) const
{
+ checkFindConfigOptionType(Name, ConfigType::BOOL);
const Item *Itm = Lookup(Name);
if (Itm == 0 || Itm->Value.empty() == true)
return Default;
@@ -774,7 +932,8 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool const &AsSectio
if ((*I == '/' && I + 1 != End && I[1] == '/') ||
(*I == '#' && strcmp(string(I,I+6).c_str(),"#clear") != 0 &&
- strcmp(string(I,I+8).c_str(),"#include") != 0))
+ strcmp(string(I,I+8).c_str(),"#include") != 0 &&
+ strcmp(string(I,I+strlen("#x-apt-configure-index")).c_str(), "#x-apt-configure-index") != 0))
{
End = I;
break;
@@ -889,7 +1048,7 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool const &AsSectio
{
Stack.push(ParentTag);
- /* Make sectional tags incorperate the section into the
+ /* Make sectional tags incorporate the section into the
tag string */
if (AsSectional == true && Word.empty() == false)
{
@@ -939,6 +1098,11 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool const &AsSectio
return _error->Error(_("Syntax error %s:%u: Included from here"),FName.c_str(),CurLine);
}
}
+ else if (Tag == "x-apt-configure-index")
+ {
+ if (LoadConfigurationIndex(Word) == false)
+ return _error->Warning("Loading the configure index %s in file %s:%u failed!", Word.c_str(), FName.c_str(), CurLine);
+ }
else
return _error->Error(_("Syntax error %s:%u: Unsupported directive '%s'"),FName.c_str(),CurLine,Tag.c_str());
}