860 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			860 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 2018 MariaDB Corporation Ab
 | |
|  *
 | |
|  * Use of this software is governed by the Business Source License included
 | |
|  * in the LICENSE.TXT file and at www.mariadb.com/bsl11.
 | |
|  *
 | |
|  * Change Date: 2024-11-16
 | |
|  *
 | |
|  * On the date above, in accordance with the Business Source License, use
 | |
|  * of this software will be governed by version 2 or later of the General
 | |
|  * Public License.
 | |
|  */
 | |
| 
 | |
| #include <maxscale/config2.hh>
 | |
| #include "internal/config.hh"
 | |
| 
 | |
| using namespace std;
 | |
| 
 | |
| namespace
 | |
| {
 | |
| 
 | |
| using namespace config;
 | |
| 
 | |
| bool is_core_param(Specification::Kind kind, const std::string& param)
 | |
| {
 | |
|     bool rv = false;
 | |
| 
 | |
|     const MXS_MODULE_PARAM* pzCore_params = nullptr;
 | |
| 
 | |
|     switch (kind)
 | |
|     {
 | |
|     case Specification::FILTER:
 | |
|         pzCore_params = config_filter_params;
 | |
|         break;
 | |
| 
 | |
|     case Specification::MONITOR:
 | |
|         pzCore_params = config_monitor_params;
 | |
|         break;
 | |
| 
 | |
|     case Specification::ROUTER:
 | |
|         pzCore_params = config_service_params;
 | |
|         break;
 | |
| 
 | |
|     default:
 | |
|         mxb_assert(!true);
 | |
|     }
 | |
| 
 | |
|     if (pzCore_params)
 | |
|     {
 | |
|         while (!rv && pzCore_params->name)
 | |
|         {
 | |
|             const char* zCore_param = pzCore_params->name;
 | |
| 
 | |
|             rv = (param == zCore_param);
 | |
|             ++pzCore_params;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return rv;
 | |
| }
 | |
| }
 | |
| 
 | |
| namespace config
 | |
| {
 | |
| 
 | |
| /**
 | |
|  * class Specification
 | |
|  */
 | |
| Specification::Specification(const char* zModule, Kind kind)
 | |
|     : m_module(zModule)
 | |
|     , m_kind(kind)
 | |
| {
 | |
| }
 | |
| 
 | |
| Specification::~Specification()
 | |
| {
 | |
| }
 | |
| 
 | |
| const string& Specification::module() const
 | |
| {
 | |
|     return m_module;
 | |
| }
 | |
| 
 | |
| const Param* Specification::find_param(const string& name) const
 | |
| {
 | |
|     auto it = m_params.find(name);
 | |
| 
 | |
|     return it != m_params.end() ? it->second : nullptr;
 | |
| }
 | |
| 
 | |
| ostream& Specification::document(ostream& out) const
 | |
| {
 | |
|     for (const auto& entry : m_params)
 | |
|     {
 | |
|         out << entry.second->documentation() << endl;
 | |
|     }
 | |
| 
 | |
|     return out;
 | |
| }
 | |
| 
 | |
| bool Specification::validate(const MXS_CONFIG_PARAMETER& params) const
 | |
| {
 | |
|     bool valid = true;
 | |
| 
 | |
|     set<string> provided;
 | |
| 
 | |
|     for (const auto& param : params)
 | |
|     {
 | |
|         const auto& name = param.first;
 | |
|         const auto& value = param.second;
 | |
| 
 | |
|         const Param* pParam = find_param(name.c_str());
 | |
| 
 | |
|         if (pParam)
 | |
|         {
 | |
|             bool param_valid = true;
 | |
|             string message;
 | |
| 
 | |
|             if (!pParam->validate(value.c_str(), &message))
 | |
|             {
 | |
|                 param_valid = false;
 | |
|             }
 | |
| 
 | |
|             if (!message.empty())
 | |
|             {
 | |
|                 if (param_valid)
 | |
|                 {
 | |
|                     MXS_WARNING("%s: %s", name.c_str(), message.c_str());
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     MXS_ERROR("%s: %s", name.c_str(), message.c_str());
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             provided.insert(name);
 | |
|         }
 | |
|         else if (!is_core_param(m_kind, name))
 | |
|         {
 | |
|             MXS_WARNING("%s: The parameter '%s' is unrecognized.", m_module.c_str(), name.c_str());
 | |
|             valid = false;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     for (const auto& entry : m_params)
 | |
|     {
 | |
|         const Param* pParam = entry.second;
 | |
| 
 | |
|         if (pParam->is_mandatory() && (provided.find(pParam->name()) == provided.end()))
 | |
|         {
 | |
|             MXS_ERROR("%s: The mandatory parameter '%s' is not provided.",
 | |
|                       m_module.c_str(), pParam->name().c_str());
 | |
|             valid = false;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return valid;
 | |
| }
 | |
| 
 | |
| bool Specification::configure(Configuration& configuration, const MXS_CONFIG_PARAMETER& params) const
 | |
| {
 | |
|     mxb_assert(validate(params));
 | |
|     mxb_assert(size() == configuration.size());
 | |
| 
 | |
|     bool configured = true;
 | |
| 
 | |
|     for (const auto& param : params)
 | |
|     {
 | |
|         const auto& name = param.first;
 | |
| 
 | |
|         if (!is_core_param(m_kind, name))
 | |
|         {
 | |
|             const auto& value = param.second;
 | |
| 
 | |
|             const Param* pParam = find_param(name.c_str());
 | |
|             config::Type* pValue = configuration.find_value(name.c_str());
 | |
| 
 | |
|             mxb_assert(pValue && pParam);   // Should have been validated.
 | |
|             mxb_assert(&pValue->parameter() == pParam);
 | |
| 
 | |
|             if (pParam && pValue)
 | |
|             {
 | |
|                 if (!pParam->set(*pValue, value.c_str()))
 | |
|                 {
 | |
|                     mxb_assert(!true);
 | |
|                     configured = false;
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 MXS_ERROR("%s: The parameter '%s' is unrecognized.", m_module.c_str(), name.c_str());
 | |
|                 configured = false;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (configured)
 | |
|     {
 | |
|         configured = configuration.post_configure(params);
 | |
|     }
 | |
| 
 | |
|     return configured;
 | |
| }
 | |
| 
 | |
| void Specification::populate(MXS_MODULE& module) const
 | |
| {
 | |
|     MXS_MODULE_PARAM* pModule_param = &module.parameters[0];
 | |
| 
 | |
|     for (const auto& entry : m_params)
 | |
|     {
 | |
|         const Param* pParam = entry.second;
 | |
| 
 | |
|         pParam->populate(*pModule_param);
 | |
|         ++pModule_param;
 | |
|     }
 | |
| }
 | |
| 
 | |
| size_t Specification::size() const
 | |
| {
 | |
|     return m_params.size();
 | |
| }
 | |
| 
 | |
| void Specification::insert(Param* pParam)
 | |
| {
 | |
|     mxb_assert(m_params.find(pParam->name()) == m_params.end());
 | |
| 
 | |
|     m_params.insert(make_pair(pParam->name(), pParam));
 | |
| }
 | |
| 
 | |
| void Specification::remove(Param* pParam)
 | |
| {
 | |
|     auto it = m_params.find(pParam->name());
 | |
|     mxb_assert(it != m_params.end());
 | |
| 
 | |
|     m_params.erase(it);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * class Param
 | |
|  */
 | |
| Param::Param(Specification* pSpecification,
 | |
|              const char* zName,
 | |
|              const char* zDescription,
 | |
|              Kind kind,
 | |
|              mxs_module_param_type legacy_type)
 | |
|     : m_specification(*pSpecification)
 | |
|     , m_name(zName)
 | |
|     , m_description(zDescription)
 | |
|     , m_kind(kind)
 | |
|     , m_legacy_type(legacy_type)
 | |
| {
 | |
|     m_specification.insert(this);
 | |
| }
 | |
| 
 | |
| Param::~Param()
 | |
| {
 | |
|     m_specification.remove(this);
 | |
| }
 | |
| 
 | |
| const string& Param::name() const
 | |
| {
 | |
|     return m_name;
 | |
| }
 | |
| 
 | |
| const string& Param::description() const
 | |
| {
 | |
|     return m_description;
 | |
| }
 | |
| 
 | |
| std::string Param::documentation() const
 | |
| {
 | |
|     std::stringstream ss;
 | |
| 
 | |
|     ss << m_name << " (" << type() << ", ";
 | |
| 
 | |
|     if (is_mandatory())
 | |
|     {
 | |
|         ss << "mandatory";
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         ss << "optional, default: " << default_to_string();
 | |
|     }
 | |
| 
 | |
|     ss << "): " << m_description;
 | |
| 
 | |
|     return ss.str();
 | |
| }
 | |
| 
 | |
| Param::Kind Param::kind() const
 | |
| {
 | |
|     return m_kind;
 | |
| }
 | |
| 
 | |
| bool Param::is_mandatory() const
 | |
| {
 | |
|     return m_kind == MANDATORY;
 | |
| }
 | |
| 
 | |
| bool Param::is_optional() const
 | |
| {
 | |
|     return m_kind == OPTIONAL;
 | |
| }
 | |
| 
 | |
| bool Param::has_default_value() const
 | |
| {
 | |
|     return is_optional();
 | |
| }
 | |
| 
 | |
| void Param::populate(MXS_MODULE_PARAM& param) const
 | |
| {
 | |
|     param.type = m_legacy_type;
 | |
|     param.name = MXS_STRDUP_A(name().c_str());
 | |
| 
 | |
|     if (has_default_value())
 | |
|     {
 | |
|         string s = default_to_string().c_str();
 | |
| 
 | |
|         if ((s.length() >= 2) && (s.at(0) == '"') && (s.at(s.length() - 1) == '"'))
 | |
|         {
 | |
|             s = s.substr(1, s.length() - 2);
 | |
|         }
 | |
| 
 | |
|         param.default_value = MXS_STRDUP_A(s.c_str());
 | |
|     }
 | |
| 
 | |
|     if (is_mandatory())
 | |
|     {
 | |
|         param.options |= MXS_MODULE_OPT_REQUIRED;
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * class Configuration
 | |
|  */
 | |
| Configuration::Configuration(const std::string& name, const config::Specification* pSpecification)
 | |
|     : m_name(name)
 | |
|     , m_specification(*pSpecification)
 | |
| {
 | |
| }
 | |
| 
 | |
| const std::string& Configuration::name() const
 | |
| {
 | |
|     return m_name;
 | |
| }
 | |
| 
 | |
| const config::Specification& Configuration::specification() const
 | |
| {
 | |
|     return m_specification;
 | |
| }
 | |
| 
 | |
| Type* Configuration::find_value(const string& name)
 | |
| {
 | |
|     auto it = m_values.find(name);
 | |
| 
 | |
|     return it != m_values.end() ? it->second : nullptr;
 | |
| }
 | |
| 
 | |
| const Type* Configuration::find_value(const string& name) const
 | |
| {
 | |
|     return const_cast<Configuration*>(this)->find_value(name);
 | |
| }
 | |
| 
 | |
| ostream& Configuration::persist(ostream& out) const
 | |
| {
 | |
|     for (const auto& entry : m_values)
 | |
|     {
 | |
|         Type* pValue = entry.second;
 | |
|         pValue->persist(out) << "\n";
 | |
|     }
 | |
| 
 | |
|     return out;
 | |
| }
 | |
| 
 | |
| void Configuration::insert(Type* pValue)
 | |
| {
 | |
|     mxb_assert(m_values.find(pValue->parameter().name()) == m_values.end());
 | |
| 
 | |
|     m_values.insert(make_pair(pValue->parameter().name(), pValue));
 | |
| }
 | |
| 
 | |
| void Configuration::remove(Type* pValue, const std::string& name)
 | |
| {
 | |
|     auto it = m_values.find(name);
 | |
| 
 | |
|     mxb_assert(it != m_values.end());
 | |
|     mxb_assert(it->second == pValue);
 | |
|     m_values.erase(it);
 | |
| }
 | |
| 
 | |
| bool Configuration::post_configure(const MXS_CONFIG_PARAMETER& params)
 | |
| {
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| size_t Configuration::size() const
 | |
| {
 | |
|     return m_values.size();
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * class Type
 | |
|  */
 | |
| Type::Type(Configuration* pConfiguration, const config::Param* pParam)
 | |
|     : m_configuration(*pConfiguration)
 | |
|     , m_param(*pParam)
 | |
|     , m_name(pParam->name())
 | |
| {
 | |
|     // The name is copied, so that we have access to it in the destructor
 | |
|     // also in the case that Param happens to be destructed first.
 | |
|     m_configuration.insert(this);
 | |
| }
 | |
| 
 | |
| Type::~Type()
 | |
| {
 | |
|     m_configuration.remove(this, m_name);
 | |
| }
 | |
| 
 | |
| const config::Param& Type::parameter() const
 | |
| {
 | |
|     return m_param;
 | |
| }
 | |
| 
 | |
| ostream& Type::persist(ostream& out) const
 | |
| {
 | |
|     out << m_param.name() << "=" << to_string();
 | |
|     return out;
 | |
| }
 | |
| 
 | |
| bool Type::set(const string& value_as_string)
 | |
| {
 | |
|     return m_param.set(*this, value_as_string);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * ParamBool
 | |
|  */
 | |
| std::string ParamBool::type() const
 | |
| {
 | |
|     return "boolean";
 | |
| }
 | |
| 
 | |
| std::string ParamBool::default_to_string() const
 | |
| {
 | |
|     return to_string(m_default_value);
 | |
| }
 | |
| 
 | |
| bool ParamBool::validate(const std::string& value_as_string, std::string* pMessage) const
 | |
| {
 | |
|     value_type value;
 | |
|     return from_string(value_as_string, &value, pMessage);
 | |
| }
 | |
| 
 | |
| bool ParamBool::set(Type& value, const std::string& value_as_string) const
 | |
| {
 | |
|     mxb_assert(&value.parameter() == this);
 | |
| 
 | |
|     Bool& bool_value = static_cast<Bool&>(value);
 | |
| 
 | |
|     value_type x;
 | |
|     bool valid = from_string(value_as_string, &x);
 | |
| 
 | |
|     if (valid)
 | |
|     {
 | |
|         bool_value.set(x);
 | |
|     }
 | |
| 
 | |
|     return valid;
 | |
| }
 | |
| 
 | |
| bool ParamBool::from_string(const string& value_as_string, value_type* pValue, string* pMessage) const
 | |
| {
 | |
|     int rv = config_truth_value(value_as_string.c_str());
 | |
| 
 | |
|     if (rv == 1)
 | |
|     {
 | |
|         *pValue = true;
 | |
|     }
 | |
|     else if (rv == 0)
 | |
|     {
 | |
|         *pValue = false;
 | |
|     }
 | |
|     else if (pMessage)
 | |
|     {
 | |
|         mxb_assert(rv == -1);
 | |
| 
 | |
|         *pMessage = "Invalid boolean: ";
 | |
|         *pMessage += value_as_string;
 | |
|     }
 | |
| 
 | |
|     return rv != -1;
 | |
| }
 | |
| 
 | |
| string ParamBool::to_string(value_type value) const
 | |
| {
 | |
|     return value ? "true" : "false";
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * ParamNumber
 | |
|  */
 | |
| std::string ParamNumber::default_to_string() const
 | |
| {
 | |
|     return to_string(m_default_value);
 | |
| }
 | |
| 
 | |
| bool ParamNumber::validate(const std::string& value_as_string, std::string* pMessage) const
 | |
| {
 | |
|     value_type value;
 | |
|     return from_string(value_as_string, &value, pMessage);
 | |
| }
 | |
| 
 | |
| bool ParamNumber::set(Type& value, const std::string& value_as_string) const
 | |
| {
 | |
|     mxb_assert(&value.parameter() == this);
 | |
| 
 | |
|     Number& number_value = static_cast<Number&>(value);
 | |
| 
 | |
|     value_type x;
 | |
|     bool valid = from_string(value_as_string, &x);
 | |
| 
 | |
|     if (valid)
 | |
|     {
 | |
|         number_value.set(x);
 | |
|     }
 | |
| 
 | |
|     return valid;
 | |
| }
 | |
| 
 | |
| bool ParamNumber::from_string(const std::string& value_as_string,
 | |
|                               value_type* pValue,
 | |
|                               std::string* pMessage) const
 | |
| {
 | |
|     const char* zValue = value_as_string.c_str();
 | |
|     char* zEnd;
 | |
|     long l = strtol(zValue, &zEnd, 10);
 | |
|     bool valid = (l >= m_min_value && l <= m_max_value && zEnd != zValue && *zEnd == 0);
 | |
| 
 | |
|     if (valid)
 | |
|     {
 | |
|         *pValue = l;
 | |
|     }
 | |
|     else if (pMessage)
 | |
|     {
 | |
|         if (!(zEnd != zValue && *zEnd == 0))
 | |
|         {
 | |
|             *pMessage = "Invalid ";
 | |
|         }
 | |
|         else if (!(l >= m_min_value))
 | |
|         {
 | |
|             *pMessage = "Too small a ";
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             mxb_assert(!(l <= m_max_value));
 | |
|             *pMessage = "Too large a ";
 | |
|         }
 | |
| 
 | |
|         *pMessage += type();
 | |
|         *pMessage += ": ";
 | |
|         *pMessage += value_as_string;
 | |
|     }
 | |
| 
 | |
|     return valid;
 | |
| }
 | |
| 
 | |
| std::string ParamNumber::to_string(value_type value) const
 | |
| {
 | |
|     return std::to_string(value);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * ParamCount
 | |
|  */
 | |
| std::string ParamCount::type() const
 | |
| {
 | |
|     return "count";
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * ParamInteger
 | |
|  */
 | |
| std::string ParamInteger::type() const
 | |
| {
 | |
|     return "integer";
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * ParamPath
 | |
|  */
 | |
| std::string ParamPath::type() const
 | |
| {
 | |
|     return "path";
 | |
| }
 | |
| 
 | |
| std::string ParamPath::default_to_string() const
 | |
| {
 | |
|     return to_string(m_default_value);
 | |
| }
 | |
| 
 | |
| bool ParamPath::validate(const std::string& value_as_string, std::string* pMessage) const
 | |
| {
 | |
|     value_type value;
 | |
|     return from_string(value_as_string, &value, pMessage);
 | |
| }
 | |
| 
 | |
| bool ParamPath::set(Type& value, const std::string& value_as_string) const
 | |
| {
 | |
|     mxb_assert(&value.parameter() == this);
 | |
| 
 | |
|     Path& path_value = static_cast<Path&>(value);
 | |
| 
 | |
|     value_type x;
 | |
|     bool valid = from_string(value_as_string, &x);
 | |
| 
 | |
|     if (valid)
 | |
|     {
 | |
|         path_value.set(x);
 | |
|     }
 | |
| 
 | |
|     return valid;
 | |
| }
 | |
| 
 | |
| bool ParamPath::from_string(const std::string& value_as_string,
 | |
|                             value_type* pValue,
 | |
|                             std::string* pMessage) const
 | |
| {
 | |
|     MXS_MODULE_PARAM param {};
 | |
|     param.options = m_options;
 | |
| 
 | |
|     bool valid = check_path_parameter(¶m, value_as_string.c_str());
 | |
| 
 | |
|     if (valid)
 | |
|     {
 | |
|         *pValue = value_as_string;
 | |
|     }
 | |
|     else if (pMessage)
 | |
|     {
 | |
|         *pMessage = "Invalid path (does not exist, required permissions are not granted, ";
 | |
|         *pMessage += "or cannot be created): ";
 | |
|         *pMessage += value_as_string;
 | |
|     }
 | |
| 
 | |
|     return valid;
 | |
| }
 | |
| 
 | |
| std::string ParamPath::to_string(const value_type& value) const
 | |
| {
 | |
|     return value;
 | |
| }
 | |
| 
 | |
| void ParamPath::populate(MXS_MODULE_PARAM& param) const
 | |
| {
 | |
|     Param::populate(param);
 | |
| 
 | |
|     param.options |= m_options;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * ParamServer
 | |
|  */
 | |
| std::string ParamServer::type() const
 | |
| {
 | |
|     return "server";
 | |
| }
 | |
| 
 | |
| std::string ParamServer::default_to_string() const
 | |
| {
 | |
|     return "";
 | |
| }
 | |
| 
 | |
| bool ParamServer::validate(const std::string& value_as_string, std::string* pMessage) const
 | |
| {
 | |
|     value_type value;
 | |
|     return from_string(value_as_string, &value, pMessage);
 | |
| }
 | |
| 
 | |
| bool ParamServer::set(Type& value, const std::string& value_as_string) const
 | |
| {
 | |
|     mxb_assert(&value.parameter() == this);
 | |
| 
 | |
|     Server& server_value = static_cast<Server&>(value);
 | |
| 
 | |
|     value_type x;
 | |
|     bool valid = from_string(value_as_string, &x);
 | |
| 
 | |
|     if (valid)
 | |
|     {
 | |
|         server_value.set(x);
 | |
|     }
 | |
| 
 | |
|     return valid;
 | |
| }
 | |
| 
 | |
| bool ParamServer::from_string(const std::string& value_as_string,
 | |
|                               value_type* pValue,
 | |
|                               std::string* pMessage) const
 | |
| {
 | |
|     *pValue = SERVER::find_by_unique_name(value_as_string);
 | |
| 
 | |
|     if (!*pValue && pMessage)
 | |
|     {
 | |
|         *pMessage = "Unknown server: ";
 | |
|         *pMessage += value_as_string;
 | |
|     }
 | |
| 
 | |
|     return *pValue;
 | |
| }
 | |
| 
 | |
| std::string ParamServer::to_string(value_type value) const
 | |
| {
 | |
|     return value->name();
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * ParamSize
 | |
|  */
 | |
| std::string ParamSize::type() const
 | |
| {
 | |
|     return "size";
 | |
| }
 | |
| 
 | |
| std::string ParamSize::default_to_string() const
 | |
| {
 | |
|     return to_string(m_default_value);
 | |
| }
 | |
| 
 | |
| bool ParamSize::validate(const std::string& value_as_string, std::string* pMessage) const
 | |
| {
 | |
|     value_type value;
 | |
|     return from_string(value_as_string, &value, pMessage);
 | |
| }
 | |
| 
 | |
| bool ParamSize::set(Type& value, const std::string& value_as_string) const
 | |
| {
 | |
|     mxb_assert(&value.parameter() == this);
 | |
| 
 | |
|     Size& size_value = static_cast<Size&>(value);
 | |
| 
 | |
|     value_type x;
 | |
|     bool valid = from_string(value_as_string, &x);
 | |
| 
 | |
|     if (valid)
 | |
|     {
 | |
|         size_value.set(x);
 | |
|     }
 | |
| 
 | |
|     return valid;
 | |
| }
 | |
| 
 | |
| bool ParamSize::from_string(const std::string& value_as_string,
 | |
|                             value_type* pValue,
 | |
|                             std::string* pMessage) const
 | |
| {
 | |
|     bool valid = get_suffixed_size(value_as_string.c_str(), pValue);
 | |
| 
 | |
|     if (!valid && pMessage)
 | |
|     {
 | |
|         *pMessage = "Invalid size: ";
 | |
|         *pMessage += value_as_string;
 | |
|     }
 | |
| 
 | |
|     return valid;
 | |
| }
 | |
| 
 | |
| std::string ParamSize::to_string(value_type value) const
 | |
| {
 | |
|     // TODO: Use largest possible unit.
 | |
|     return std::to_string(value);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * ParamString
 | |
|  */
 | |
| std::string ParamString::type() const
 | |
| {
 | |
|     return "string";
 | |
| }
 | |
| 
 | |
| std::string ParamString::default_to_string() const
 | |
| {
 | |
|     return to_string(m_default_value);
 | |
| }
 | |
| 
 | |
| bool ParamString::validate(const std::string& value_as_string, std::string* pMessage) const
 | |
| {
 | |
|     value_type value;
 | |
|     return from_string(value_as_string, &value, pMessage);
 | |
| }
 | |
| 
 | |
| bool ParamString::set(Type& value, const std::string& value_as_string) const
 | |
| {
 | |
|     mxb_assert(&value.parameter() == this);
 | |
| 
 | |
|     String& string_value = static_cast<String&>(value);
 | |
| 
 | |
|     value_type x;
 | |
|     bool valid = from_string(value_as_string, &x);
 | |
| 
 | |
|     if (valid)
 | |
|     {
 | |
|         string_value.set(x);
 | |
|     }
 | |
| 
 | |
|     return valid;
 | |
| }
 | |
| 
 | |
| bool ParamString::from_string(const std::string& value_as_string,
 | |
|                               value_type* pValue,
 | |
|                               std::string* pMessage) const
 | |
| {
 | |
|     bool valid = true;
 | |
| 
 | |
|     char b = value_as_string.empty() ? 0 : value_as_string.front();
 | |
|     char e = value_as_string.empty() ? 0 : value_as_string.back();
 | |
| 
 | |
|     if (b != '"' && b != '\'')
 | |
|     {
 | |
|         if (pMessage)
 | |
|         {
 | |
|             *pMessage = "A string value should be enclosed in quotes: ";
 | |
|             *pMessage += value_as_string;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     string s = value_as_string;
 | |
| 
 | |
|     if (b == '"' || b == '\'')
 | |
|     {
 | |
|         valid = (b == e);
 | |
| 
 | |
|         if (valid)
 | |
|         {
 | |
|             s = s.substr(1, s.length() - 2);
 | |
|         }
 | |
|         else if (pMessage)
 | |
|         {
 | |
|             *pMessage = "A quoted string must end with the same quote: ";
 | |
|             *pMessage += value_as_string;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (valid)
 | |
|     {
 | |
|         *pValue = s;
 | |
|     }
 | |
| 
 | |
|     return valid;
 | |
| }
 | |
| 
 | |
| std::string ParamString::to_string(value_type value) const
 | |
| {
 | |
|     stringstream ss;
 | |
|     ss << "\"" << value << "\"";
 | |
|     return ss.str();
 | |
| }
 | |
| }
 | 
