# Default yasps configuration # By default the server is bound to 0.0.0.0:7517 # -------------------------------------------------- # Server configuration bind_address=0.0.0.0 port=7517 # Authentication configuration # Unauthenticated connections are allowed by default noauth=1 username=user password=pass123
As you can see, the options require different data types. Therefore, i needed a generic algorithm that could parse the file and interpret the given values as strings, integer, bools or whatever data type i indicated, and assign them to the corresponding attribute. To achieve this, i created a small class using template parameters.
The ConfigurationParser is extremely simple to use. There is one method which adds an attribute and associates it with a pointer. Whenever that attribute name is found on the file, the parser will try to interpret the given value and store it in that pointer. The method has the following signature:
template<class T> void add_option(const std::string &name, T *value_ptr);
The only constraint imposed on the type T is that the input operator(operator>>) is defined. As long as you use either primitive types or std::string(s), you don't have to implement anything else. In case you have created a certain class that can be deserialized, you would have to implement this operator.
Once every attribute has been set, you have to call the ConfigurationParser::parse method, using the configuration file name as the argument. This is the signature of this method:
void parse(const std::string &file_name);
This method can raise different exceptions, depending on what problem was encountered:
- std::ios_base::failure if an error occurred when opening the file.
- ConfigurationParser::NoValueGivenError if no value was set for an attribute that appeared on the configuration file. e.g. bleh= . There should be some value after the '=' character.
- ConfigurationParser::InvalidValueError if there was a data type missmatch when trying to interpret an attribute's value. This can happen if, for example, an attribute expects an integer value, however, a string value is given.
- ConfigurationParser::InvalidOptionError is raised if an attribute which was not registered using ConfigurationParser::add_option appeared in the configuration file.
#include <iostream> #include <string> #include "configparser.h" using CPPUtils::ConfigurationParser; class Configuration { public: void load(const std::string &file_name) { ConfigurationParser parser; parser.add_option("username", &config_username); parser.add_option("password", &config_password); parser.add_option("bind_address", &address); parser.add_option("log_file", &log_filename); parser.add_option("port", &port); parser.add_option("noauth", &config_allow_no_auth); parser.add_option("enable_logging", &config_enable_logging); try { parser.parse(file_name); } catch(std::ios_base::failure &ex) { std::cerr << "[ERROR] Error opening " << file_name << "(" << ex.what() << ").\n"; } catch(ConfigurationParser::NoValueGivenError &ex) { std::cerr << "[ERROR] Parse error: No value give for " << ex.what() << " attribute.\n"; } catch(ConfigurationParser::InvalidValueError &ex) { std::cerr << "[ERROR] Parse error: Invalid value for attribute " << ex.what() << "\n"; } catch(ConfigurationParser::InvalidOptionError &ex) { std::cerr << "[ERROR] Parse error: Could not find a valid attribute in \"" << ex.what() << "\"\n";; } } private: std::string config_username, config_password, address, log_filename; short port; bool config_allow_no_auth, config_enable_logging; };
That's all. You can download the header file here, the source file here and the only header dependency, exception.h. The class is licensed under GPLv3, so feel free to use it.