mirror of
https://github.com/boostorg/log.git
synced 2026-02-19 14:32:31 +00:00
Merged latest changes from trunk.
[SVN r85461]
This commit is contained in:
@@ -10,62 +10,46 @@
|
||||
* \date 20.07.2012
|
||||
*
|
||||
* \brief This header is the Boost.Log library implementation, see the library documentation
|
||||
* at http://www.boost.org/libs/log/doc/log.html.
|
||||
* at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_LOG_WITHOUT_SETTINGS_PARSERS
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <locale>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <boost/ref.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <algorithm>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/exception/exception.hpp>
|
||||
#include <boost/exception/info.hpp>
|
||||
#include <boost/exception/errinfo_at_line.hpp>
|
||||
#include <boost/io/ios_state.hpp>
|
||||
#include <boost/move/core.hpp>
|
||||
#include <boost/move/utility.hpp>
|
||||
#include <boost/algorithm/string/trim.hpp>
|
||||
#include <boost/spirit/include/qi_core.hpp>
|
||||
#include <boost/spirit/include/qi_char.hpp>
|
||||
#include <boost/spirit/include/qi_lit.hpp>
|
||||
#include <boost/spirit/include/qi_eoi.hpp>
|
||||
#include <boost/spirit/include/qi_eol.hpp>
|
||||
#include <boost/spirit/include/qi_raw.hpp>
|
||||
#include <boost/spirit/include/qi_lexeme.hpp>
|
||||
#include <boost/range/iterator_range_core.hpp>
|
||||
#include <boost/log/detail/config.hpp>
|
||||
#include <boost/log/detail/code_conversion.hpp>
|
||||
#include <boost/log/exceptions.hpp>
|
||||
#include <boost/log/utility/setup/settings_parser.hpp>
|
||||
#include <boost/log/exceptions.hpp>
|
||||
#include "parser_utils.hpp"
|
||||
#include "spirit_encoding.hpp"
|
||||
#include <boost/log/detail/header.hpp>
|
||||
|
||||
namespace qi = boost::spirit::qi;
|
||||
|
||||
namespace boost {
|
||||
|
||||
BOOST_LOG_OPEN_NAMESPACE
|
||||
|
||||
BOOST_LOG_ANONYMOUS_NAMESPACE {
|
||||
|
||||
//! Settings parsing grammar
|
||||
//! Settings parser
|
||||
template< typename CharT >
|
||||
class settings_grammar :
|
||||
public qi::grammar<
|
||||
const CharT*,
|
||||
typename log::aux::encoding_specific< typename log::aux::encoding< CharT >::type >::space_type
|
||||
>
|
||||
class settings_parser
|
||||
{
|
||||
private:
|
||||
typedef CharT char_type;
|
||||
typedef const char_type* iterator_type;
|
||||
typedef log::aux::encoding_specific< typename log::aux::encoding< char_type >::type > encoding_specific;
|
||||
typedef settings_grammar< char_type > this_type;
|
||||
typedef qi::grammar< iterator_type, typename encoding_specific::space_type > base_type;
|
||||
typedef typename base_type::start_type rule_type;
|
||||
typedef typename log::aux::encoding< char_type >::type encoding;
|
||||
typedef settings_parser< char_type > this_type;
|
||||
|
||||
typedef std::basic_string< char_type > string_type;
|
||||
typedef log::aux::char_constants< char_type > constants;
|
||||
@@ -83,70 +67,101 @@ private:
|
||||
//! Current line number
|
||||
unsigned int& m_LineCounter;
|
||||
|
||||
//! A parser for a comment
|
||||
rule_type comment;
|
||||
//! A parser for a section name
|
||||
rule_type section_name;
|
||||
//! A parser for a quoted string
|
||||
rule_type quoted_string;
|
||||
//! A parser for a parameter name and value
|
||||
rule_type parameter;
|
||||
//! A parser for a single line
|
||||
rule_type line;
|
||||
|
||||
public:
|
||||
//! Constructor
|
||||
explicit settings_grammar(settings_type& setts, unsigned int& line_counter, std::locale const& loc) :
|
||||
base_type(line, "settings_grammar"),
|
||||
explicit settings_parser(settings_type& setts, unsigned int& line_counter, std::locale const& loc) :
|
||||
m_Settings(setts),
|
||||
m_Locale(loc),
|
||||
m_LineCounter(line_counter)
|
||||
{
|
||||
comment = qi::lit(constants::char_comment) >> *qi::char_;
|
||||
}
|
||||
|
||||
section_name =
|
||||
qi::raw[ qi::lit(constants::char_section_bracket_left) >> +(encoding_specific::graph - constants::char_section_bracket_right) >> constants::char_section_bracket_right ]
|
||||
[boost::bind(&this_type::set_section_name, this, _1)] >>
|
||||
-comment;
|
||||
//! Parses a line of the input
|
||||
void parse_line(iterator_type& begin, iterator_type end)
|
||||
{
|
||||
iterator_type p = begin;
|
||||
p = constants::trim_spaces_left(p, end);
|
||||
if (p != end)
|
||||
{
|
||||
char_type c = *p;
|
||||
if (c == constants::char_section_bracket_left)
|
||||
{
|
||||
// We have a section name
|
||||
iterator_type start = ++p;
|
||||
start = constants::trim_spaces_left(start, end);
|
||||
iterator_type stop = std::find(start, end, constants::char_section_bracket_right);
|
||||
if (stop == end)
|
||||
BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Section header is invalid", (m_LineCounter));
|
||||
|
||||
quoted_string = qi::lexeme
|
||||
[
|
||||
qi::lit(constants::char_quote) >>
|
||||
*(
|
||||
(qi::lit(constants::char_backslash) >> qi::char_) |
|
||||
(qi::char_ - qi::lit(constants::char_quote))
|
||||
) >>
|
||||
qi::lit(constants::char_quote)
|
||||
];
|
||||
p = stop + 1;
|
||||
stop = constants::trim_spaces_right(start, stop);
|
||||
|
||||
parameter =
|
||||
// Parameter name
|
||||
qi::raw[ qi::lexeme[ encoding_specific::alpha >> *(encoding_specific::graph - constants::char_equal) ] ]
|
||||
[boost::bind(&this_type::set_parameter_name, this, _1)] >>
|
||||
qi::lit(constants::char_equal) >>
|
||||
// Parameter value
|
||||
(
|
||||
qi::raw[ quoted_string ][boost::bind(&this_type::set_parameter_quoted_value, this, _1)] |
|
||||
qi::raw[ +encoding_specific::graph ][boost::bind(&this_type::set_parameter_value, this, _1)]
|
||||
) >>
|
||||
-comment;
|
||||
set_section_name(start, stop);
|
||||
}
|
||||
else if (c != constants::char_comment)
|
||||
{
|
||||
// We have a parameter
|
||||
iterator_type eq = std::find(p, end, constants::char_equal);
|
||||
if (eq == end)
|
||||
BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Parameter description is invalid", (m_LineCounter));
|
||||
|
||||
line = (comment | section_name | parameter) >> qi::eoi;
|
||||
// Parameter name
|
||||
set_parameter_name(p, constants::trim_spaces_right(p, eq));
|
||||
|
||||
// Parameter value
|
||||
p = constants::trim_spaces_left(eq + 1, end);
|
||||
if (p == end || *p == constants::char_comment)
|
||||
BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Parameter value is not specified", (m_LineCounter));
|
||||
|
||||
try
|
||||
{
|
||||
string_type value;
|
||||
p = constants::parse_operand(p, end, value);
|
||||
set_parameter_value(value);
|
||||
}
|
||||
catch (parse_error& e)
|
||||
{
|
||||
throw boost::enable_error_info(e) << boost::errinfo_at_line(m_LineCounter);
|
||||
}
|
||||
}
|
||||
|
||||
// In the end of the line we may have a comment
|
||||
p = constants::trim_spaces_left(p, end);
|
||||
if (p != end)
|
||||
{
|
||||
c = *p;
|
||||
if (c == constants::char_comment)
|
||||
{
|
||||
// The comment spans until the end of the line
|
||||
p = end;
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Unexpected characters in the end of the line", (m_LineCounter));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
begin = p;
|
||||
}
|
||||
|
||||
private:
|
||||
//! The method sets the parsed section name
|
||||
void set_section_name(iterator_range< iterator_type > const& sec)
|
||||
void set_section_name(iterator_type begin, iterator_type end)
|
||||
{
|
||||
// Trim square brackets
|
||||
m_SectionName = log::aux::to_narrow(string_type(sec.begin() + 1, sec.end() - 1), m_Locale);
|
||||
algorithm::trim(m_SectionName, m_Locale);
|
||||
if (m_SectionName.empty())
|
||||
// Check that the section name is valid
|
||||
if (begin == end)
|
||||
BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Section name is empty", (m_LineCounter));
|
||||
|
||||
for (iterator_type p = begin; p != end; ++p)
|
||||
{
|
||||
// The section starter is broken
|
||||
BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "The section header is invalid.", (m_LineCounter));
|
||||
char_type c = *p;
|
||||
if (c != constants::char_dot && !encoding::isalnum(c))
|
||||
BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Section name is invalid", (m_LineCounter));
|
||||
}
|
||||
|
||||
m_SectionName = log::aux::to_narrow(string_type(begin, end), m_Locale);
|
||||
|
||||
// For compatibility with Boost.Log v1, we replace the "Sink:" prefix with "Sinks."
|
||||
// so that all sink parameters are placed in the common Sinks section.
|
||||
if (m_SectionName.compare(0, 5, "Sink:") == 0)
|
||||
@@ -154,38 +169,41 @@ private:
|
||||
}
|
||||
|
||||
//! The method sets the parsed parameter name
|
||||
void set_parameter_name(iterator_range< iterator_type > const& name)
|
||||
void set_parameter_name(iterator_type begin, iterator_type end)
|
||||
{
|
||||
if (m_SectionName.empty())
|
||||
{
|
||||
// The parameter encountered before any section starter
|
||||
BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Parameters are only allowed within sections.", (m_LineCounter));
|
||||
BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Parameters are only allowed within sections", (m_LineCounter));
|
||||
}
|
||||
|
||||
m_ParameterName = log::aux::to_narrow(string_type(name.begin(), name.end()), m_Locale);
|
||||
// Check that the parameter name is valid
|
||||
if (begin == end)
|
||||
BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Parameter name is empty", (m_LineCounter));
|
||||
|
||||
iterator_type p = begin;
|
||||
if (!encoding::isalpha(*p))
|
||||
BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Parameter name is invalid", (m_LineCounter));
|
||||
for (++p; p != end; ++p)
|
||||
{
|
||||
char_type c = *p;
|
||||
if (!encoding::isgraph(c))
|
||||
BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Parameter name is invalid", (m_LineCounter));
|
||||
}
|
||||
|
||||
m_ParameterName = log::aux::to_narrow(string_type(begin, end), m_Locale);
|
||||
}
|
||||
|
||||
//! The method sets the parsed parameter value (non-quoted)
|
||||
void set_parameter_value(iterator_range< iterator_type > const& value)
|
||||
void set_parameter_value(string_type const& value)
|
||||
{
|
||||
string_type val(value.begin(), value.end());
|
||||
m_Settings[m_SectionName][m_ParameterName] = val;
|
||||
m_ParameterName.clear();
|
||||
}
|
||||
|
||||
//! The method sets the parsed parameter value (quoted)
|
||||
void set_parameter_quoted_value(iterator_range< iterator_type > const& value)
|
||||
{
|
||||
// Cut off the quotes
|
||||
string_type val(value.begin() + 1, value.end() - 1);
|
||||
constants::translate_escape_sequences(val);
|
||||
m_Settings[m_SectionName][m_ParameterName] = val;
|
||||
m_Settings[m_SectionName][m_ParameterName] = value;
|
||||
m_ParameterName.clear();
|
||||
}
|
||||
|
||||
// Assignment and copying are prohibited
|
||||
BOOST_LOG_DELETED_FUNCTION(settings_grammar(settings_grammar const&))
|
||||
BOOST_LOG_DELETED_FUNCTION(settings_grammar& operator= (settings_grammar const&))
|
||||
BOOST_DELETED_FUNCTION(settings_parser(settings_parser const&))
|
||||
BOOST_DELETED_FUNCTION(settings_parser& operator= (settings_parser const&))
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -196,9 +214,8 @@ basic_settings< CharT > parse_settings(std::basic_istream< CharT >& strm)
|
||||
{
|
||||
typedef CharT char_type;
|
||||
typedef std::basic_string< char_type > string_type;
|
||||
typedef settings_grammar< char_type > settings_grammar_type;
|
||||
typedef settings_parser< char_type > settings_parser_type;
|
||||
typedef basic_settings< char_type > settings_type;
|
||||
typedef log::aux::encoding_specific< typename log::aux::encoding< char_type >::type > encoding_specific;
|
||||
|
||||
if (!strm.good())
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument("The input stream for parsing settings is not valid"));
|
||||
@@ -209,23 +226,17 @@ basic_settings< CharT > parse_settings(std::basic_istream< CharT >& strm)
|
||||
settings_type settings;
|
||||
unsigned int line_number = 1;
|
||||
std::locale loc = strm.getloc();
|
||||
settings_grammar_type gram(settings, line_number, loc);
|
||||
settings_parser_type parser(settings, line_number, loc);
|
||||
|
||||
string_type line;
|
||||
while (!strm.eof())
|
||||
{
|
||||
std::getline(strm, line);
|
||||
algorithm::trim(line, loc);
|
||||
|
||||
if (!line.empty())
|
||||
{
|
||||
if (!qi::phrase_parse(line.c_str(), line.c_str() + line.size(), gram, encoding_specific::space))
|
||||
{
|
||||
BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Could not parse settings from stream.", (line_number));
|
||||
}
|
||||
line.clear();
|
||||
}
|
||||
const char_type* p = line.c_str();
|
||||
parser.parse_line(p, p + line.size());
|
||||
|
||||
line.clear();
|
||||
++line_number;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user