settings: configuration file processing rewrite

This commit is contained in:
Andrzej Rybczak
2014-08-28 18:57:16 +02:00
parent 8a1e4a48dd
commit 4b933b29e1
35 changed files with 1881 additions and 1446 deletions

View File

@@ -68,13 +68,13 @@ bool LocaleBasedItemSorting::operator()(const MPD::Item &a, const MPD::Item &b)
case MPD::itSong:
switch (m_sort_mode)
{
case smName:
case SortMode::Name:
result = m_cmp(*a.song, *b.song);
break;
case smMTime:
case SortMode::ModificationTime:
result = a.song->getMTime() > b.song->getMTime();
break;
case smCustomFormat:
case SortMode::CustomFormat:
result = m_cmp(a.song->toString(Config.browser_sort_format, Config.tags_separator),
b.song->toString(Config.browser_sort_format, Config.tags_separator));
break;

View File

@@ -18,10 +18,14 @@
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef NCMPCPP_UTILITY_CONVERSION_H
#define NCMPCPP_UTILITY_CONVERSION_H
#include <boost/format.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/type_traits/is_unsigned.hpp>
#include "config.h"
#include "gcc.h"
struct ConversionError
@@ -35,7 +39,7 @@ private:
std::string m_source_value;
};
struct OutOfBounds
struct OutOfBounds : std::exception
{
const std::string &errorMessage() { return m_error_message; }
@@ -43,23 +47,25 @@ struct OutOfBounds
GNUC_NORETURN static void raise(const Type &value, const Type &lbound, const Type &ubound)
{
throw OutOfBounds((boost::format(
"Value is out of bounds ([%1%, %2%] expected, %3% given)") % lbound % ubound % value).str());
"value is out of bounds ([%1%, %2%] expected, %3% given)") % lbound % ubound % value).str());
}
template <typename Type>
GNUC_NORETURN static void raiseLower(const Type &value, const Type &lbound)
{
throw OutOfBounds((boost::format(
"Value is out of bounds ([%1%, ->) expected, %2% given)") % lbound % value).str());
"value is out of bounds ([%1%, ->) expected, %2% given)") % lbound % value).str());
}
template <typename Type>
GNUC_NORETURN static void raiseUpper(const Type &value, const Type &ubound)
{
throw OutOfBounds((boost::format(
"Value is out of bounds ((<-, %1%] expected, %2% given)") % ubound % value).str());
"value is out of bounds ((<-, %1%] expected, %2% given)") % ubound % value).str());
}
virtual const char *what() const noexcept OVERRIDE { return m_error_message.c_str(); }
private:
OutOfBounds(std::string msg) : m_error_message(msg) { }
@@ -115,3 +121,5 @@ void upperBoundCheck(const Type &value, const Type &ubound)
if (value > ubound)
OutOfBounds::raiseUpper(value, ubound);
}
#endif // NCMPCPP_UTILITY_CONVERSION_H

37
src/utility/functional.h Normal file
View File

@@ -0,0 +1,37 @@
/***************************************************************************
* Copyright (C) 2008-2014 by Andrzej Rybczak *
* electricityispower@gmail.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef NCMPCPP_UTILITY_FUNCTIONAL_H
#define NCMPCPP_UTILITY_FUNCTIONAL_H
#include <utility>
// identity function object
struct id_
{
template <typename ValueT>
constexpr auto operator()(ValueT &&v) const noexcept
-> decltype(std::forward<ValueT>(v))
{
return std::forward<ValueT>(v);
}
};
#endif // NCMPCPP_UTILITY_FUNCTIONAL_H

View File

@@ -0,0 +1,82 @@
/***************************************************************************
* Copyright (C) 2008-2014 by Andrzej Rybczak *
* electricityispower@gmail.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include <boost/regex.hpp>
#include <iostream>
#include "utility/option_parser.h"
bool option_parser::run(std::istream &is)
{
// quoted value. leftmost and rightmost quotation marks are the delimiters.
boost::regex quoted("(\\w+)\\h*=\\h*\"(.*)\"[^\"]*");
// unquoted value. whitespaces get trimmed.
boost::regex unquoted("(\\w+)\\h*=\\h*(.*?)\\h*");
boost::smatch match;
std::string line;
while (std::getline(is, line))
{
if (boost::regex_match(line, match, quoted)
|| boost::regex_match(line, match, unquoted))
{
std::string option = match[1];
auto it = m_parsers.find(option);
if (it != m_parsers.end())
{
try {
it->second.parse(match[2]);
} catch (std::exception &e) {
std::cerr << "Error while processing option \"" << option << "\": " << e.what() << "\n";
return false;
}
}
else
{
std::cerr << "Unknown option: " << option << "\n";
return false;
}
}
}
for (auto &p : m_parsers)
{
if (!p.second.defined())
{
try {
p.second.run_default();
} catch (std::exception &e) {
std::cerr << "Error while finalizing option \"" << p.first << "\": " << e.what() << "\n";
return false;
}
}
}
return true;
}
option_parser::worker yes_no(bool &arg, bool value)
{
return option_parser::worker([&arg](std::string &&v) {
if (v == "yes")
arg = true;
else if (v == "no")
arg = false;
else
throw std::runtime_error("invalid argument: " + v);
}, defaults_to(arg, value));
}

131
src/utility/option_parser.h Normal file
View File

@@ -0,0 +1,131 @@
/***************************************************************************
* Copyright (C) 2008-2014 by Andrzej Rybczak *
* electricityispower@gmail.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef NCMPCPP_UTILITY_OPTION_PARSER_H
#define NCMPCPP_UTILITY_OPTION_PARSER_H
#include <boost/lexical_cast.hpp>
#include <cassert>
#include <stdexcept>
#include <unordered_map>
#include "helpers.h"
#include "strbuffer.h"
#include "utility/functional.h"
struct option_parser
{
typedef std::function<void(std::string &&)> parser_t;
typedef std::function<void()> default_t;
struct worker
{
worker() { }
template <typename ParserT, typename DefaultT>
worker(ParserT &&p, DefaultT &&d)
: m_defined(false), m_parser(std::forward<ParserT>(p))
, m_default(std::forward<DefaultT>(d)) { }
template <typename ValueT>
void parse(ValueT &&value)
{
if (m_defined)
throw std::runtime_error("option already defined");
m_parser(std::forward<ValueT>(value));
m_defined = true;
}
bool defined() const { return m_defined; }
void run_default() const { m_default(); }
private:
bool m_defined;
parser_t m_parser;
default_t m_default;
};
template <typename ParserT, typename DefaultT>
void add(const std::string &option, ParserT &&p, DefaultT &&d)
{
assert(m_parsers.count(option) == 0);
m_parsers[option] = worker(std::forward<ParserT>(p), std::forward<DefaultT>(d));
}
template <typename WorkerT>
void add(const std::string &option, WorkerT &&w)
{
assert(m_parsers.count(option) == 0);
m_parsers[option] = std::forward<WorkerT>(w);
}
bool run(std::istream &is);
private:
std::unordered_map<std::string, worker> m_parsers;
};
template <typename IntermediateT, typename ArgT, typename TransformT>
option_parser::parser_t assign(ArgT &arg, TransformT map = id_())
{
return [&arg, map](std::string &&v) {
try {
arg = map(boost::lexical_cast<IntermediateT>(v));
} catch (boost::bad_lexical_cast &) {
throw std::runtime_error("invalid value: " + v);
}
};
}
template <typename ArgT, typename ValueT>
option_parser::default_t defaults_to(ArgT &arg, ValueT &&value)
{
return [&arg, value] {
arg = std::move(value);
};
}
template <typename IntermediateT, typename ArgT, typename ValueT, typename TransformT>
option_parser::worker assign_default(ArgT &arg, ValueT &&value, TransformT map)
{
return option_parser::worker(
assign<IntermediateT>(arg, map), defaults_to(arg, map(std::forward<ValueT>(value)))
);
}
template <typename ArgT, typename ValueT>
option_parser::worker assign_default(ArgT &arg, ValueT &&value)
{
return assign_default<ArgT>(arg, std::forward<ValueT>(value), id_());
}
// workers for specific types
template <typename ValueT, typename TransformT>
option_parser::worker buffer(NC::Buffer &arg, ValueT &&value, TransformT map)
{
return option_parser::worker(assign<std::string>(arg, [&arg, map](std::string &&s) {
return map(stringToBuffer(s));
}), defaults_to(arg, map(std::forward<ValueT>(value))));
}
option_parser::worker yes_no(bool &arg, bool value);
#endif // NCMPCPP_UTILITY_OPTION_PARSER_H