while (1)
{
ch = next();
- if (isalnum(ch))
+ if (isalnum(ch) || (varname.empty() && ch == '#'))
varname.push_back(ch);
else if (ch == ';')
break;
throw CoreException("Parse error");
}
}
- std::map<std::string, std::string>::iterator var = stack.vars.find(varname);
- if (var == stack.vars.end())
- throw CoreException("Undefined XML entity reference '&" + varname + ";'");
- value.append(var->second);
+ if (varname.empty())
+ throw CoreException("Empty XML entity reference");
+ else if (varname[0] == '#' && (varname.size() == 1 || (varname.size() == 2 && varname[1] == 'x')))
+ throw CoreException("Empty numeric character reference");
+ else if (varname[0] == '#')
+ {
+ const char* cvarname = varname.c_str();
+ char* endptr;
+ unsigned long lvalue;
+ if (cvarname[1] == 'x')
+ lvalue = strtoul(cvarname + 2, &endptr, 16);
+ else
+ lvalue = strtoul(cvarname + 1, &endptr, 10);
+ if (*endptr != '\0' || lvalue > 255)
+ throw CoreException("Invalid numeric character reference '&" + varname + ";'");
+ value.push_back(static_cast<char>(lvalue));
+ }
+ else
+ {
+ insp::flat_map<std::string, std::string>::iterator var = stack.vars.find(varname);
+ if (var == stack.vars.end())
+ throw CoreException("Undefined XML entity reference '&" + varname + ";'");
+ value.append(var->second);
+ }
}
else if (ch == '\\' && (flags & FLAG_USE_COMPAT))
{
std::set<std::string> seen;
tag = ConfigTag::create(name, current.filename, current.line, items);
- while (kv(items, seen));
+ while (kv(items, seen))
+ {
+ // Do nothing here (silences a GCC warning).
+ }
if (name == mandatory_tag)
{
flags |= FLAG_NO_INC;
if (tag->getBool("noexec", false))
flags |= FLAG_NO_EXEC;
- if (!ParseFile(name, flags, mandatorytag))
+ if (!ParseFile(ServerInstance->Config->Paths.PrependConfig(name), flags, mandatorytag))
throw CoreException("Included");
}
else if (tag->readString("executable", name))
flags |= FLAG_NO_INC;
if (tag->getBool("noexec", true))
flags |= FLAG_NO_EXEC;
- if (!ParseExec(name, flags, mandatorytag))
+ if (!ParseFile(name, flags, mandatorytag, true))
throw CoreException("Included");
}
}
if (exec && (flags & FLAG_NO_EXEC))
throw CoreException("Invalid <execfiles> tag in file included with noexec=\"yes\"");
- FileWrapper file(exec ? popen(name.c_str(), "r") : fopen(name.c_str(), "r"), exec);
+ std::string path = ServerInstance->Config->Paths.PrependConfig(name);
+ FileWrapper file(exec ? popen(name.c_str(), "r") : fopen(path.c_str(), "r"), exec);
if (!file)
- throw CoreException("Could not read \"" + name + "\" for \"" + key + "\" file");
+ throw CoreException("Could not read \"" + path + "\" for \"" + key + "\" file");
file_cache& cache = FilesOutput[key];
cache.clear();
}
}
-bool ParseStack::ParseFile(const std::string& name, int flags, const std::string& mandatory_tag)
+bool ParseStack::ParseFile(const std::string& path, int flags, const std::string& mandatory_tag, bool isexec)
{
- ServerInstance->Logs->Log("CONFIG", LOG_DEBUG, "Reading file %s", name.c_str());
- for (unsigned int t = 0; t < reading.size(); t++)
- {
- if (std::string(name) == reading[t])
- {
- throw CoreException("File " + name + " is included recursively (looped inclusion)");
- }
- }
+ ServerInstance->Logs->Log("CONFIG", LOG_DEBUG, "Reading (isexec=%d) %s", isexec, path.c_str());
+ if (stdalgo::isin(reading, path))
+ throw CoreException((isexec ? "Executable " : "File ") + path + " is included recursively (looped inclusion)");
/* It's not already included, add it to the list of files we've loaded */
- FileWrapper file(fopen(name.c_str(), "r"));
+ FileWrapper file((isexec ? popen(path.c_str(), "r") : fopen(path.c_str(), "r")), isexec);
if (!file)
- throw CoreException("Could not read \"" + name + "\" for include");
+ throw CoreException("Could not read \"" + path + "\" for include");
- reading.push_back(name);
- Parser p(*this, flags, file, name, mandatory_tag);
- bool ok = p.outer_parse();
- reading.pop_back();
- return ok;
-}
-
-bool ParseStack::ParseExec(const std::string& name, int flags, const std::string& mandatory_tag)
-{
- ServerInstance->Logs->Log("CONFIG", LOG_DEBUG, "Reading executable %s", name.c_str());
- for (unsigned int t = 0; t < reading.size(); t++)
- {
- if (std::string(name) == reading[t])
- {
- throw CoreException("Executable " + name + " is included recursively (looped inclusion)");
- }
- }
-
- /* It's not already included, add it to the list of files we've loaded */
-
- FileWrapper file(popen(name.c_str(), "r"), true);
- if (!file)
- throw CoreException("Could not open executable \"" + name + "\" for include");
-
- reading.push_back(name);
- Parser p(*this, flags, file, name, mandatory_tag);
+ reading.push_back(path);
+ Parser p(*this, flags, file, path, mandatory_tag);
bool ok = p.outer_parse();
reading.pop_back();
return ok;
bool ConfigTag::readString(const std::string& key, std::string& value, bool allow_lf)
{
- if (!this)
- return false;
for(std::vector<KeyVal>::iterator j = items.begin(); j != items.end(); ++j)
{
if(j->first != key)
return res;
}
-long ConfigTag::getInt(const std::string &key, long def)
+long ConfigTag::getInt(const std::string &key, long def, long min, long max)
{
std::string result;
if(!readString(key, result))
switch (toupper(*res_tail))
{
case 'K':
- res= res* 1024;
+ res = res * 1024;
break;
case 'M':
- res= res* 1024 * 1024;
+ res = res * 1024 * 1024;
break;
case 'G':
- res= res* 1024 * 1024 * 1024;
+ res = res * 1024 * 1024 * 1024;
break;
}
+
+ CheckRange(key, res, def, min, max);
return res;
}
+void ConfigTag::CheckRange(const std::string& key, long& res, long def, long min, long max)
+{
+ if (res < min || res > max)
+ {
+ ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, "WARNING: <%s:%s> value of %ld is not between %ld and %ld; set to %ld.",
+ tag.c_str(), key.c_str(), res, min, max, def);
+ res = def;
+ }
+}
+
+long ConfigTag::getDuration(const std::string& key, long def, long min, long max)
+{
+ std::string duration;
+ if (!readString(key, duration))
+ return def;
+
+ long ret = InspIRCd::Duration(duration);
+ CheckRange(key, ret, def, min, max);
+ return ret;
+}
+
double ConfigTag::getFloat(const std::string &key, double def)
{
std::string result;
return src_name + ":" + ConvToStr(src_line);
}
-ConfigTag* ConfigTag::create(const std::string& Tag, const std::string& file, int line, std::vector<KeyVal>*&items)
+ConfigTag* ConfigTag::create(const std::string& Tag, const std::string& file, int line, std::vector<KeyVal>*& Items)
{
ConfigTag* rv = new ConfigTag(Tag, file, line);
- items = &rv->items;
+ Items = &rv->items;
return rv;
}