diff options
author | Naram Qashat cyberbotx@cyberbotx.com <Naram Qashat cyberbotx@cyberbotx.com@5417fbe8-f217-4b02-8779-1006273d7864> | 2008-10-03 22:06:58 +0000 |
---|---|---|
committer | Naram Qashat cyberbotx@cyberbotx.com <Naram Qashat cyberbotx@cyberbotx.com@5417fbe8-f217-4b02-8779-1006273d7864> | 2008-10-03 22:06:58 +0000 |
commit | 6b7161fbdff30af0519730ba75e75bf82786597d (patch) | |
tree | 07cca7564830a7a63bad345256819c8a391acf35 /src | |
parent | f09953561bebb310cfe6a534c1262d77433a4e42 (diff) |
Started framework for new config reader, based on hottpd by w00t, copied over from my own fork that was in progress.
git-svn-id: http://anope.svn.sourceforge.net/svnroot/anope/trunk@1409 5417fbe8-f217-4b02-8779-1006273d7864
Diffstat (limited to 'src')
-rw-r--r-- | src/config.c | 705 |
1 files changed, 701 insertions, 4 deletions
diff --git a/src/config.c b/src/config.c index 49d3897ec..b4b9c5f0e 100644 --- a/src/config.c +++ b/src/config.c @@ -6,13 +6,14 @@ * Please read COPYING and README for further details. * * Based on the original code of Epona by Lara. - * Based on the original code of Services by Andy Church. - * - * $Id$ + * Based on the original code of Services by Andy Church. + * + * $Id$ * */ #include "services.h" +#include "configreader.h" /*************************************************************************/ @@ -277,7 +278,7 @@ int ModulesDelayedNumber; char **ModulesDelayedAutoload; /** - * Core Module Stuff + * Core Module Stuff **/ char *HostCoreModules; char **HostServCoreModules; @@ -353,6 +354,702 @@ int UseTS6; /*************************************************************************/ +ServerConfig::ServerConfig() : include_stack(), errstr(""), newconfig(), config_data() +{ + this->ClearStack(); +} + +void ServerConfig::ClearStack() +{ + include_stack.clear(); +} + +bool ServerConfig::CheckOnce(const char *tag) +{ + int count = ConfValueEnum(config_data, tag); + if (count > 1) { + throw ConfigException(static_cast<std::string>("You have more than one <") + tag + "> tag, this is not permitted."); + } + if (count < 1) { + throw ConfigException(static_cast<std::string>("You have not defined a <") + tag + "> tag, this is required."); + } + return true; +} + +bool NoValidation(ServerConfig *, const char *, const char *, ValueItem &) +{ + return true; +} + +bool DoneConfItem(ServerConfig *, const char *) +{ + return true; +} + +void ServerConfig::ValidateNoSpaces(const char *p, const std::string &tag, const std::string &val) +{ + for (const char *ptr = p; *ptr; ++ptr) if (*ptr == ' ') throw ConfigException(static_cast<std::string>("The value of <") + tag + ":" + val + + "> cannot contain spaces"); +} + +/* NOTE: Before anyone asks why we're not using inet_pton for this, it is because inet_pton and friends do not return so much detail, + * even in strerror(errno). They just return 'yes' or 'no' to an address without such detail as to whats WRONG with the address. + * Because ircd users arent as technical as they used to be (;)) we are going to give more of a useful error message. + */ +void ServerConfig::ValidateIP(const char *p, const std::string &tag, const std::string &val, bool wild) +{ + int num_dots = 0, num_seps = 0; + bool not_numbers = false, not_hex = false; + if (*p) { + if (*p == '.') throw ConfigException(static_cast<std::string>("The value of <") + tag + ":" + val + "> is not an IP address"); + for (const char *ptr = p; *ptr; ++ptr) { + if (wild && (*ptr == '*' || *ptr == '?' || *ptr == '/')) continue; + if (*ptr != ':' && *ptr != '.') { + if (*ptr < '0' || *ptr > '9') { + not_numbers = true; + if (toupper(*ptr) < 'A' || toupper(*ptr) > 'F') not_hex = true; + } + } + switch (*ptr) { + case ' ': + throw ConfigException(static_cast<std::string>("The value of <") + tag + ":" + val + "> is not an IP address"); + case '.': + ++num_dots; + break; + case ':': + ++num_seps; + } + } + if (num_dots > 3) throw ConfigException(static_cast<std::string>("The value of <") + tag + ":" + val + + "> is an IPv4 address with too many fields!"); + if (num_seps > 8) throw ConfigException(static_cast<std::string>("The value of <") + tag + ":" + val + + "> is an IPv6 address with too many fields!"); + if (!num_seps && num_dots < 3 && !wild) throw ConfigException(static_cast<std::string>("The value of <") + tag + ":" + val + + "> looks to be a malformed IPv4 address"); + if (!num_seps && num_dots == 3 && not_numbers) throw ConfigException(static_cast<std::string>("The value of <") + tag + ":" + val + + "> contains non-numeric characters in an IPv4 address"); + if (num_seps && not_hex) throw ConfigException(static_cast<std::string>("The value of <") + tag + ":" + val + + "> contains non-hexdecimal characters in an IPv6 address"); + if (num_seps && num_dots != 3 && num_dots && !wild) throw ConfigException(static_cast<std::string>("The value of <") + tag + ":" + val + + "> is a malformed IPv6 4in6 address"); + } +} + +void ServerConfig::ValidateHostname(const char *p, const std::string &tag, const std::string &val) +{ + int num_dots = 0; + if (*p) { + if (*p == '.') throw ConfigException(static_cast<std::string>("The value of <") + tag + ":" + val + "> is not a valid hostname"); + for (const char *ptr = p; *ptr; ++ptr) { + switch (*ptr) { + case ' ': + throw ConfigException(static_cast<std::string>("The value of <") + tag + ":" + val + "> is not a valid hostname"); + case '.': + ++num_dots; + } + } + if (!num_dots) throw ConfigException(static_cast<std::string>("The value of <") + tag + ":" + val + "> is not a valid hostname"); + } +} + +bool ValidateMaxTargets(ServerConfig *, const char *, const char *, ValueItem &data) +{ + if (data.GetInteger() < 0 || data.GetInteger() > 31) { + alog("WARNING: <options:maxtargets> value is greater than 31 or less than 0, set to 20."); + data.Set(20); + } + return true; +} + +bool ValidateNotEmpty(ServerConfig *, const char *tag, const char *value, ValueItem &data) +{ + if (!*data.GetString()) throw ConfigException(static_cast<std::string>("The value for <") + tag + ":" + value + "> cannot be empty!"); + return true; +} + +bool ValidatePort(ServerConfig *, const char *tag, const char *value, ValueItem &data) +{ + int port = data.GetInteger(); + if (!port) return true; + if (port < 1 || port > 65535) throw ConfigException(static_cast<std::string>("The value for <") + tag + ":" + value + + "> is not a value port, it must be between 1 and 65535!"); + return true; +} + +void ServerConfig::ReportConfigError(const std::string &errormessage, bool bail) +{ + alog("There were errors in your configuration file: %s", errormessage.c_str()); + if (bail) { + // TODO -- Need a way to stop loading in a safe way -- CyberBotX + //ServerInstance->Exit(EXIT_STATUS_CONFIG); + } +} + +int ServerConfig::Read(bool bail) +{ + errstr.clear(); + // These tags MUST occur and must ONLY occur once in the config file + static const char *Once[] = {NULL}; + // These tags can occur ONCE or not at all + InitialConfig Values[] = { + {NULL, NULL, NULL, NULL, DT_NOTHING, NoValidation} + }; + /* These tags can occur multiple times, and therefore they have special code to read them + * which is different to the code for reading the singular tags listed above. */ + MultiConfig MultiValues[] = { + {NULL, + {NULL}, + {NULL}, + {0}, + NULL, NULL, NULL} + }; + // Load and parse the config file, if there are any errors then explode + // Make a copy here so if it fails then we can carry on running with an unaffected config + newconfig.clear(); + if (LoadConf(newconfig, SERVICES_CONF, errstr)) { + // If we succeeded, set the ircd config to the new one + config_data = newconfig; + } + else { + ReportConfigError(errstr.str(), bail); + return 0; + } + // The stuff in here may throw CoreException, be sure we're in a position to catch it. + try { + // Read the values of all the tags which occur once or not at all, and call their callbacks. + for (int Index = 0; Values[Index].tag; ++Index) { + char item[BUFSIZE]; + int dt = Values[Index].datatype; + bool allow_newlines = dt & DT_ALLOW_NEWLINE, allow_wild = dt & DT_ALLOW_WILD; + dt &= ~DT_ALLOW_NEWLINE; + dt &= ~DT_ALLOW_WILD; + ConfValue(config_data, Values[Index].tag, Values[Index].value, Values[Index].default_value, 0, item, BUFSIZE, allow_newlines); + ValueItem vi(item); + if (!Values[Index].validation_function(this, Values[Index].tag, Values[Index].value, vi)) + throw ConfigException("One or more values in your configuration file failed to validate. Please see your ircd.log for more information."); + switch (dt) { + case DT_NOSPACES: { + ValueContainerChar *vcc = dynamic_cast<ValueContainerChar *>(Values[Index].val); + ValidateNoSpaces(vi.GetString(), Values[Index].tag, Values[Index].value); + vcc->Set(vi.GetString(), strlen(vi.GetString()) + 1); + } + break; + case DT_HOSTNAME: { + ValueContainerChar *vcc = dynamic_cast<ValueContainerChar *>(Values[Index].val); + ValidateHostname(vi.GetString(), Values[Index].tag, Values[Index].value); + vcc->Set(vi.GetString(), strlen(vi.GetString()) + 1); + } + break; + case DT_IPADDRESS: { + ValueContainerChar *vcc = dynamic_cast<ValueContainerChar *>(Values[Index].val); + ValidateIP(vi.GetString(), Values[Index].tag, Values[Index].value, allow_wild); + vcc->Set(vi.GetString(), strlen(vi.GetString()) + 1); + } + break; + case DT_CHARPTR: { + ValueContainerChar *vcc = dynamic_cast<ValueContainerChar *>(Values[Index].val); + // Make sure we also copy the null terminator + vcc->Set(vi.GetString(), strlen(vi.GetString()) + 1); + } + break; + case DT_STRING: { + ValueContainerString *vcs = dynamic_cast<ValueContainerString *>(Values[Index].val); + vcs->Set(vi.GetString()); + } + break; + case DT_INTEGER: { + int val = vi.GetInteger(); + ValueContainerInt *vci = dynamic_cast<ValueContainerInt *>(Values[Index].val); + vci->Set(&val, sizeof(int)); + } + break; + case DT_UINTEGER: { + unsigned val = vi.GetInteger(); + ValueContainerUInt *vci = dynamic_cast<ValueContainerUInt *>(Values[Index].val); + vci->Set(&val, sizeof(int)); + } + break; + case DT_TIME: { + time_t time = dotime(vi.GetString()); + ValueContainerTime *vci = dynamic_cast<ValueContainerTime *>(Values[Index].val); + vci->Set(&time, sizeof(time_t)); + } + break; + case DT_BOOLEAN: { + bool val = vi.GetBool(); + ValueContainerBool *vcb = dynamic_cast<ValueContainerBool *>(Values[Index].val); + vcb->Set(&val, sizeof(bool)); + } + break; + default: + break; + } + // We're done with this now + delete Values[Index].val; + } + /* Read the multiple-tag items (class tags, connect tags, etc) + * and call the callbacks associated with them. We have three + * callbacks for these, a 'start', 'item' and 'end' callback. */ + for (int Index = 0; MultiValues[Index].tag; ++Index) { + MultiValues[Index].init_function(this, MultiValues[Index].tag); + int number_of_tags = ConfValueEnum(config_data, MultiValues[Index].tag); + for (int tagnum = 0; tagnum < number_of_tags; ++tagnum) { + ValueList vl; + for (int valuenum = 0; MultiValues[Index].items[valuenum]; ++valuenum) { + int dt = MultiValues[Index].datatype[valuenum]; + bool allow_newlines = dt & DT_ALLOW_NEWLINE, allow_wild = dt & DT_ALLOW_WILD; + dt &= ~DT_ALLOW_NEWLINE; + dt &= ~DT_ALLOW_WILD; + switch (dt) { + case DT_NOSPACES: { + char item[BUFSIZE]; + if (ConfValue(config_data, MultiValues[Index].tag, MultiValues[Index].items[valuenum], + MultiValues[Index].items_default[valuenum], tagnum, item, BUFSIZE, allow_newlines)) { + vl.push_back(ValueItem(item)); + } + else vl.push_back(ValueItem("")); + ValidateNoSpaces(vl[vl.size() - 1].GetString(), MultiValues[Index].tag, MultiValues[Index].items[valuenum]); + } + break; + case DT_HOSTNAME: { + char item[BUFSIZE]; + if (ConfValue(config_data, MultiValues[Index].tag, MultiValues[Index].items[valuenum], + MultiValues[Index].items_default[valuenum], tagnum, item, BUFSIZE, allow_newlines)) { + vl.push_back(ValueItem(item)); + } + else vl.push_back(ValueItem("")); + ValidateHostname(vl[vl.size() - 1].GetString(), MultiValues[Index].tag, MultiValues[Index].items[valuenum]); + } + break; + case DT_IPADDRESS: { + char item[BUFSIZE]; + if (ConfValue(config_data, MultiValues[Index].tag, MultiValues[Index].items[valuenum], + MultiValues[Index].items_default[valuenum], tagnum, item, BUFSIZE, allow_newlines)) { + vl.push_back(ValueItem(item)); + } + else vl.push_back(ValueItem("")); + ValidateIP(vl[vl.size() - 1].GetString(), MultiValues[Index].tag, MultiValues[Index].items[valuenum], allow_wild); + } + break; + case DT_CHARPTR: { + char item[BUFSIZE]; + if (ConfValue(config_data, MultiValues[Index].tag, MultiValues[Index].items[valuenum], + MultiValues[Index].items_default[valuenum], tagnum, item, BUFSIZE, allow_newlines)) { + vl.push_back(ValueItem(item)); + } + else vl.push_back(ValueItem("")); + } + break; + case DT_STRING: { + std::string item; + if (ConfValue(config_data, static_cast<std::string>(MultiValues[Index].tag), + static_cast<std::string>(MultiValues[Index].items[valuenum]), + static_cast<std::string>(MultiValues[Index].items_default[valuenum]), tagnum, item, allow_newlines)) { + vl.push_back(ValueItem(item)); + } + else vl.push_back(ValueItem("")); + } + break; + case DT_INTEGER: + case DT_UINTEGER: { + int item = 0; + if (ConfValueInteger(config_data, MultiValues[Index].tag, MultiValues[Index].items[valuenum], + MultiValues[Index].items_default[valuenum], tagnum, item)) vl.push_back(ValueItem(item)); + else vl.push_back(ValueItem(0)); + } + break; + case DT_TIME: { + std::string item; + if (ConfValue(config_data, static_cast<std::string>(MultiValues[Index].tag), + static_cast<std::string>(MultiValues[Index].items[valuenum]), + static_cast<std::string>(MultiValues[Index].items_default[valuenum]), tagnum, item, allow_newlines)) { + int time = dotime(item.c_str()); + vl.push_back(ValueItem(time)); + } + else vl.push_back(ValueItem(0)); + } + break; + case DT_BOOLEAN: { + bool item = ConfValueBool(config_data, MultiValues[Index].tag, MultiValues[Index].items[valuenum], + MultiValues[Index].items_default[valuenum], tagnum); + vl.push_back(ValueItem(item)); + } + } + } + MultiValues[Index].validation_function(this, MultiValues[Index].tag, static_cast<const char **>(MultiValues[Index].items), vl, + MultiValues[Index].datatype); + } + MultiValues[Index].finish_function(this, MultiValues[Index].tag); + } + } + catch (ConfigException &ce) { + ReportConfigError(ce.GetReason(), bail); + return 0; + } + if (debug) alog("End config"); + for (int Index = 0; Once[Index]; ++Index) if (!CheckOnce(Once[Index])) return 0; + alog("Done reading configuration file."); + return 1; +} + +bool ServerConfig::LoadConf(ConfigDataHash &target, const char *filename, std::ostringstream &errorstream) +{ + std::string line, wordbuffer, section, itemname; + std::ifstream conf(filename); + int linenumber = 0; + bool in_word = false, in_quote = false, in_ml_comment = false; + KeyValList sectiondata; + if (conf.fail()) { + errorstream << "File " << filename << " could not be opened." << std::endl; + return false; + } + if (debug) alog("Start to read conf %s", filename); + // Start reading characters... + while (getline(conf, line)) { + ++linenumber; + unsigned c = 0, len = line.size(); + for (; c < len; ++c) { + char ch = line[c]; + if (in_quote) { + if (ch == '"') { + in_quote = in_word = false; + continue; + } + wordbuffer += ch; + continue; + } + if (in_ml_comment) { + if (ch == '*' && c + 1 < len && line[c + 1] == '/') { + in_ml_comment = false; + ++c; + } + continue; + } + if (ch == '#' || (ch == '/' && c + 1 < len && line[c + 1] == '/')) break; // Line comment, ignore the rest of the line (much like this one!) + else if (ch == '/' && c + 1 < len && line[c + 1] == '*') { + // Multiline (or less than one line) comment + in_ml_comment = true; + ++c; + continue; + } + else if (ch == '"') { + // Quotes are valid only in the value position + if (section.empty() || itemname.empty()) { + errorstream << "Unexpected quoted string: " << filename << ":" << linenumber << std::endl; + return false; + } + if (in_word || !wordbuffer.empty()) { + errorstream << "Unexpected quoted string (prior unhandled words): " << filename << ":" << linenumber << std::endl; + return false; + } + in_quote = in_word = true; + continue; + } + else if (ch == '=') { + if (section.empty()) { + errorstream << "Config item outside of section (or stray '='): " << filename << ":" << linenumber << std::endl; + return false; + } + if (!itemname.empty()) { + errorstream << "Stray '=' sign or item without value: " << filename << ":" << linenumber << std::endl; + return false; + } + if (in_word) in_word = false; + itemname = wordbuffer; + wordbuffer.clear(); + } + else if (ch == '{') { + if (!section.empty()) { + errorstream << "Section inside another section: " << filename << ":" << linenumber << std::endl; + return false; + } + if (wordbuffer.empty()) { + errorstream << "Section without a name or unexpected '{': " << filename << ":" << linenumber << std::endl; + return false; + } + if (in_word) in_word = false; + section = wordbuffer; + wordbuffer.clear(); + } + else if (ch == '}') { + if (section.empty()) { + errorstream << "Stray '}': " << filename << ":" << linenumber << std::endl; + return false; + } + if (!wordbuffer.empty() || !itemname.empty()) { + errorstream << "Unexpected end of section: " << filename << ":" << linenumber << std::endl; + return false; + } + target.insert(std::pair<std::string, KeyValList>(section, sectiondata)); + section.clear(); + sectiondata.clear(); + } + else if (ch == ';' || ch == '\r') continue; // Ignore + else if (ch == ' ' || ch == '\t') { + // Terminate word + if (in_word) in_word = false; + } + else { + if (!in_word && !wordbuffer.empty()) { + errorstream << "Unexpected word: " << filename << ":" << linenumber << std::endl; + return false; + } + wordbuffer += ch; + in_word = true; + } + } + if (in_quote) { + // Quotes can span multiple lines; all we need to do is go to the next line without clearing things + wordbuffer += "\n"; + continue; + } + in_word = false; + if (!itemname.empty()) { + if (wordbuffer.empty()) { + errorstream << "Item without value: " << filename << ":" << linenumber << std::endl; + return false; + } + if (debug) alog("ln %d EOL: s='%s' '%s' set to '%s'", linenumber, section.c_str(), itemname.c_str(), wordbuffer.c_str()); + sectiondata.push_back(KeyVal(itemname, wordbuffer)); + wordbuffer.clear(); + itemname.clear(); + } + } + if (in_ml_comment) { + errorstream << "Unterminated multiline comment at end of file: " << filename << std::endl; + return false; + } + if (in_quote) { + errorstream << "Unterminated quote at end of file: " << filename << std::endl; + return false; + } + if (!itemname.empty() || !wordbuffer.empty()) { + errorstream << "Unexpected garbage at end of file: " << filename << std::endl; + return false; + } + if (!section.empty()) { + errorstream << "Unterminated section at end of file: " << filename << std::endl; + return false; + } + return true; +} + +bool ServerConfig::LoadConf(ConfigDataHash &target, const std::string &filename, std::ostringstream &errorstream) +{ + return LoadConf(target, filename.c_str(), errorstream); +} + +bool ServerConfig::ConfValue(ConfigDataHash &target, const char *tag, const char *var, int index, char *result, int length, bool allow_linefeeds) +{ + return ConfValue(target, tag, var, "", index, result, length, allow_linefeeds); +} + +bool ServerConfig::ConfValue(ConfigDataHash &target, const char *tag, const char *var, const char *default_value, int index, char *result, + int length, bool allow_linefeeds) +{ + std::string value; + bool r = ConfValue(target, static_cast<std::string>(tag), static_cast<std::string>(var), static_cast<std::string>(default_value), index, value, + allow_linefeeds); + strlcpy(result, value.c_str(), length); + return r; +} + +bool ServerConfig::ConfValue(ConfigDataHash &target, const std::string &tag, const std::string &var, int index, std::string &result, + bool allow_linefeeds) +{ + return ConfValue(target, tag, var, "", index, result, allow_linefeeds); +} + +bool ServerConfig::ConfValue(ConfigDataHash &target, const std::string &tag, const std::string &var, const std::string &default_value, int index, + std::string &result, bool allow_linefeeds) +{ + ConfigDataHash::size_type pos = index; + if (pos < target.count(tag)) { + ConfigDataHash::iterator iter = target.find(tag); + for (int i = 0; i < index; ++i) ++iter; + KeyValList::iterator j = iter->second.begin(), jend = iter->second.end(); + for (; j != jend; ++j) { + if (j->first == var) { + if (!allow_linefeeds && j->second.find('\n') != std::string::npos) { + alog("Value of <%s:%s> contains a linefeed, and linefeeds in this value are not permitted -- stripped to spaces.", tag.c_str(), var.c_str()); + std::string::iterator n = j->second.begin(), nend = j->second.end(); + for (; n != nend; ++n) if (*n == '\n') *n = ' '; + } + else { + result = j->second; + return true; + } + } + } + if (!default_value.empty()) { + result = default_value; + return true; + } + } + else if (!pos) { + if (!default_value.empty()) { + result = default_value; + return true; + } + } + return false; +} + +bool ServerConfig::ConfValueInteger(ConfigDataHash &target, const char *tag, const char *var, int index, int &result) +{ + return ConfValueInteger(target, static_cast<std::string>(tag), static_cast<std::string>(var), "", index, result); +} + +bool ServerConfig::ConfValueInteger(ConfigDataHash &target, const char *tag, const char *var, const char *default_value, int index, int &result) +{ + return ConfValueInteger(target, static_cast<std::string>(tag), static_cast<std::string>(var), static_cast<std::string>(default_value), index, + result); +} + +bool ServerConfig::ConfValueInteger(ConfigDataHash &target, const std::string &tag, const std::string &var, int index, int &result) +{ + return ConfValueInteger(target, tag, var, "", index, result); +} + +bool ServerConfig::ConfValueInteger(ConfigDataHash &target, const std::string &tag, const std::string &var, const std::string &default_value, int index, int &result) +{ + std::string value; + std::istringstream stream; + bool r = ConfValue(target, tag, var, default_value, index, value); + stream.str(value); + if (!(stream >> result)) return false; + else { + if (!value.empty()) { + if (value.substr(0, 2) == "0x") { + char *endptr; + value.erase(0, 2); + result = strtol(value.c_str(), &endptr, 16); + /* No digits found */ + if (endptr == value.c_str()) return false; + } + else { + char denominator = *(value.end() - 1); + switch (toupper(denominator)) { + case 'K': + // Kilobytes -> bytes + result = result * 1024; + break; + case 'M': + // Megabytes -> bytes + result = result * 1048576; + break; + case 'G': + // Gigabytes -> bytes + result = result * 1073741824; + break; + } + } + } + } + return r; +} + +bool ServerConfig::ConfValueBool(ConfigDataHash &target, const char *tag, const char *var, int index) +{ + return ConfValueBool(target, static_cast<std::string>(tag), static_cast<std::string>(var), "", index); +} + +bool ServerConfig::ConfValueBool(ConfigDataHash &target, const char *tag, const char *var, const char *default_value, int index) +{ + return ConfValueBool(target, static_cast<std::string>(tag), static_cast<std::string>(var), static_cast<std::string>(default_value), index); +} + +bool ServerConfig::ConfValueBool(ConfigDataHash &target, const std::string &tag, const std::string &var, int index) +{ + return ConfValueBool(target, tag, var, "", index); +} + +bool ServerConfig::ConfValueBool(ConfigDataHash &target, const std::string &tag, const std::string &var, const std::string &default_value, int index) +{ + std::string result; + if (!ConfValue(target, tag, var, default_value, index, result)) return false; + return result == "yes" || result == "true" || result == "1"; +} + +int ServerConfig::ConfValueEnum(ConfigDataHash &target, const char *tag) +{ + return target.count(tag); +} + +int ServerConfig::ConfValueEnum(ConfigDataHash &target, const std::string &tag) +{ + return target.count(tag); +} + +int ServerConfig::ConfVarEnum(ConfigDataHash &target, const char *tag, int index) +{ + return ConfVarEnum(target, static_cast<std::string>(tag), index); +} + +int ServerConfig::ConfVarEnum(ConfigDataHash &target, const std::string &tag, int index) +{ + ConfigDataHash::size_type pos = index; + if (pos < target.count(tag)) { + ConfigDataHash::const_iterator iter = target.find(tag); + for (int i = 0; i < index; ++i) ++iter; + return iter->second.size(); + } + return 0; +} + +ValueItem::ValueItem(int value) : v("") +{ + std::stringstream n; + n << value; + v = n.str(); +} + +ValueItem::ValueItem(bool value) : v("") +{ + std::stringstream n; + n << value; + v = n.str(); +} + +ValueItem::ValueItem(const char *value) : v(value) { } + +ValueItem::ValueItem(const std::string &value) : v(value) { } + +void ValueItem::Set(const char *value) +{ + v = value; +} + +void ValueItem::Set(const std::string &value) +{ + v = value; +} + +void ValueItem::Set(int value) +{ + std::stringstream n; + n << value; + v = n.str(); +} + +int ValueItem::GetInteger() +{ + if (v.empty()) return 0; + return atoi(v.c_str()); +} + +char *ValueItem::GetString() +{ + return const_cast<char *>(v.c_str()); +} + +bool ValueItem::GetBool() +{ + return GetInteger() || v == "yes" || v == "true"; +} + +/*************************************************************************/ + /* Deprecated directive (dep_) and value checking (chk_) functions: */ /* Hey, there are no left! -GD */ |