2
0
mirror of https://github.com/boostorg/log.git synced 2026-02-11 11:52:20 +00:00

Merged latest changes from trunk.

[SVN r85461]
This commit is contained in:
Andrey Semashev
2013-08-25 14:20:22 +00:00
parent cdd85fc887
commit 5204873fa9
294 changed files with 3184 additions and 1462 deletions

View File

@@ -10,12 +10,11 @@
* \date 07.04.2008
*
* \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 <ctime>
#include <map>
#include <string>
#include <sstream>
@@ -26,14 +25,6 @@
#include <boost/move/utility.hpp>
#include <boost/optional/optional.hpp>
#include <boost/utility/in_place_factory.hpp>
#include <boost/range/iterator_range_core.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_raw.hpp>
#include <boost/spirit/include/qi_lexeme.hpp>
#include <boost/spirit/include/qi_as.hpp>
#include <boost/spirit/include/qi_symbols.hpp>
#include <boost/phoenix/core.hpp>
#include <boost/phoenix/operator.hpp>
#include <boost/log/expressions/message.hpp>
@@ -56,8 +47,6 @@
#endif
#include <boost/log/detail/header.hpp>
namespace qi = boost::spirit::qi;
namespace boost {
BOOST_LOG_OPEN_NAMESPACE
@@ -161,18 +150,16 @@ private:
//! Formatter parsing grammar
template< typename CharT >
class formatter_grammar :
public qi::grammar< const CharT* >
class formatter_parser
{
private:
typedef CharT char_type;
typedef const char_type* iterator_type;
typedef qi::grammar< iterator_type > base_type;
typedef typename base_type::start_type rule_type;
typedef std::basic_string< char_type > string_type;
typedef basic_formatter< char_type > formatter_type;
typedef boost::log::aux::char_constants< char_type > constants;
typedef log::aux::encoding_specific< typename log::aux::encoding< char_type >::type > encoding_specific;
typedef typename log::aux::encoding< char_type >::type encoding;
typedef log::aux::encoding_specific< encoding > encoding_specific;
typedef formatter_factory< char_type > formatter_factory_type;
typedef typename formatter_factory_type::args_map args_map;
@@ -190,88 +177,74 @@ private:
//! Argument value
mutable string_type m_ArgValue;
//! A parser for a quoted string argument value
rule_type quoted_string_arg_value;
//! A parser for an argument value
rule_type arg_value;
//! A parser for a named argument
rule_type arg;
//! A parser for an optional argument list for a formatter
rule_type arg_list;
//! A parser for an attribute placeholder
rule_type attr_name;
//! A parser for the complete formatter expression
rule_type expression;
public:
//! Constructor
formatter_grammar() :
base_type(expression)
formatter_parser()
{
quoted_string_arg_value = qi::raw
[
// A quoted string with C-style escape sequences support
qi::lit(constants::char_quote) >>
*(
(qi::lit(constants::char_backslash) >> qi::char_) |
(qi::char_ - qi::lit(constants::char_quote))
) >>
qi::lit(constants::char_quote)
]
[boost::bind(&formatter_grammar::on_quoted_string_arg_value, this, _1)];
}
arg_value =
(
quoted_string_arg_value |
qi::raw[ *(encoding_specific::graph - constants::char_comma - constants::char_paren_bracket_left - constants::char_paren_bracket_right) ]
[boost::bind(&formatter_grammar::on_arg_value, this, _1)]
);
//! Parses formatter
void parse(iterator_type& begin, iterator_type end)
{
iterator_type p = begin;
arg =
(
*encoding_specific::space >>
qi::raw[ encoding_specific::alpha >> *encoding_specific::alnum ][boost::bind(&formatter_grammar::on_arg_name, this, _1)] >>
*encoding_specific::space >>
constants::char_equal >>
*encoding_specific::space >>
arg_value >>
*encoding_specific::space
);
while (p != end)
{
// Find the end of a string literal
iterator_type start = p;
for (; p != end; ++p)
{
char_type c = *p;
if (c == constants::char_backslash)
{
// We found an escaped character
++p;
if (p == end)
BOOST_LOG_THROW_DESCR(parse_error, "Invalid escape sequence in the formatter string");
}
else if (c == constants::char_percent)
{
// We found an attribute
break;
}
}
arg_list =
(
qi::lit(constants::char_paren_bracket_left) >>
(arg[boost::bind(&formatter_grammar::push_arg, this)] % qi::lit(constants::char_comma)) >>
qi::lit(constants::char_paren_bracket_right)
);
if (start != p)
push_string(start, p);
attr_name =
(
qi::lit(constants::char_percent) >>
(
qi::raw[ qi::lit(constants::message_text_keyword()) ]
[boost::bind(&formatter_grammar::on_attr_name, this, _1)] |
(
qi::raw[ +(encoding_specific::print - constants::char_paren_bracket_left - constants::char_percent) ]
[boost::bind(&formatter_grammar::on_attr_name, this, _1)] >>
-arg_list
)
) >>
qi::lit(constants::char_percent)
)
[boost::bind(&formatter_grammar::push_attr, this)];
if (p != end)
{
// We found an attribute placeholder
iterator_type start = constants::trim_spaces_left(++p, end);
p = constants::scan_attr_placeholder(start, end);
if (p == end)
BOOST_LOG_THROW_DESCR(parse_error, "Invalid attribute placeholder in the formatter string");
expression =
(
qi::raw
[
*(
(qi::lit(constants::char_backslash) >> qi::char_) |
(qi::char_ - qi::lit(constants::char_quote) - qi::lit(constants::char_percent))
)
][boost::bind(&formatter_grammar::push_string, this, _1)] %
attr_name
);
on_attribute_name(start, p);
p = constants::trim_spaces_left(p, end);
if (p == end)
BOOST_LOG_THROW_DESCR(parse_error, "Invalid attribute placeholder in the formatter string");
if (*p == constants::char_paren_bracket_left)
{
// We found formatter arguments
p = parse_args(constants::trim_spaces_left(++p, end), end);
p = constants::trim_spaces_left(p, end);
if (p == end)
BOOST_LOG_THROW_DESCR(parse_error, "Invalid attribute placeholder in the formatter string");
}
if (*p != constants::char_percent)
BOOST_LOG_THROW_DESCR(parse_error, "Invalid attribute placeholder in the formatter string");
++p;
push_attr();
}
}
begin = p;
}
//! Returns the parsed formatter
@@ -287,23 +260,79 @@ public:
}
private:
//! The method parses formatter arguments
iterator_type parse_args(iterator_type begin, iterator_type end)
{
iterator_type p = begin;
if (p == end)
BOOST_LOG_THROW_DESCR(parse_error, "Invalid attribute placeholder arguments description in the formatter string");
if (*p == constants::char_paren_bracket_right)
return ++p;
while (true)
{
char_type c = *p;
// Read argument name
iterator_type start = p;
if (!encoding::isalpha(*p))
BOOST_LOG_THROW_DESCR(parse_error, "Placeholder argument name is invalid");
for (++p; p != end; ++p)
{
c = *p;
if (encoding::isspace(c) || c == constants::char_equal)
break;
if (!encoding::isalnum(c) && c != constants::char_underline)
BOOST_LOG_THROW_DESCR(parse_error, "Placeholder argument name is invalid");
}
if (start == p)
BOOST_LOG_THROW_DESCR(parse_error, "Placeholder argument name is empty");
on_arg_name(start, p);
p = constants::trim_spaces_left(p, end);
if (p == end || *p != constants::char_equal)
BOOST_LOG_THROW_DESCR(parse_error, "Placeholder argument description is not valid");
// Read argument value
start = p = constants::trim_spaces_left(++p, end);
p = constants::parse_operand(p, end, m_ArgValue);
if (p == start)
BOOST_LOG_THROW_DESCR(parse_error, "Placeholder argument value is not specified");
push_arg();
p = constants::trim_spaces_left(p, end);
if (p == end)
BOOST_LOG_THROW_DESCR(parse_error, "Invalid attribute placeholder arguments description in the formatter string");
c = *p;
if (c == constants::char_paren_bracket_right)
{
break;
}
else if (c == constants::char_comma)
{
p = constants::trim_spaces_left(++p, end);
if (p == end)
BOOST_LOG_THROW_DESCR(parse_error, "Placeholder argument name is invalid");
}
else
{
BOOST_LOG_THROW_DESCR(parse_error, "Invalid attribute placeholder arguments description in the formatter string");
}
}
return ++p;
}
//! The method is called when an argument name is discovered
void on_arg_name(iterator_range< iterator_type > const& name)
void on_arg_name(iterator_type begin, iterator_type end)
{
m_ArgName.assign(name.begin(), name.end());
}
//! The method is called when an argument value is discovered
void on_quoted_string_arg_value(iterator_range< iterator_type > const& value)
{
// Cut off the quotes
m_ArgValue.assign(value.begin() + 1, value.end() - 1);
constants::translate_escape_sequences(m_ArgValue);
}
//! The method is called when an argument value is discovered
void on_arg_value(iterator_range< iterator_type > const& value)
{
m_ArgValue.assign(value.begin(), value.end());
m_ArgName.assign(begin, end);
}
//! The method is called when an argument is filled
void push_arg()
{
@@ -313,16 +342,22 @@ private:
}
//! The method is called when an attribute name is discovered
void on_attr_name(iterator_range< iterator_type > const& name)
void on_attribute_name(iterator_type begin, iterator_type end)
{
if (name.empty())
if (begin == end)
BOOST_LOG_THROW_DESCR(parse_error, "Empty attribute name encountered");
// For compatibility with Boost.Log v1 we recognize %_% as the message attribute name
if (std::char_traits< char_type >::compare(constants::message_text_keyword(), name.begin(), name.size()) == 0)
const std::size_t len = end - begin;
if (std::char_traits< char_type >::length(constants::message_text_keyword()) == len &&
std::char_traits< char_type >::compare(constants::message_text_keyword(), begin, len) == 0)
{
m_AttrName = log::aux::default_attribute_names::message();
}
else
m_AttrName = attribute_name(log::aux::to_narrow(string_type(name.begin(), name.end())));
{
m_AttrName = attribute_name(log::aux::to_narrow(string_type(begin, end)));
}
}
//! The method is called when an attribute is filled
void push_attr()
@@ -348,14 +383,11 @@ private:
}
//! The method is called when a string literal is discovered
void push_string(iterator_range< iterator_type > const& str)
void push_string(iterator_type begin, iterator_type end)
{
if (!str.empty())
{
string_type s(str.begin(), str.end());
constants::translate_escape_sequences(s);
append_formatter(expressions::stream << s);
}
string_type s(begin, end);
constants::translate_escape_sequences(s);
append_formatter(expressions::stream << s);
}
//! The method appends a formatter part to the final formatter
@@ -369,8 +401,8 @@ private:
}
// Assignment and copying are prohibited
BOOST_LOG_DELETED_FUNCTION(formatter_grammar(formatter_grammar const&))
BOOST_LOG_DELETED_FUNCTION(formatter_grammar& operator= (formatter_grammar const&))
BOOST_DELETED_FUNCTION(formatter_parser(formatter_parser const&))
BOOST_DELETED_FUNCTION(formatter_parser& operator= (formatter_parser const&))
};
} // namespace
@@ -383,7 +415,7 @@ void register_formatter_factory(attribute_name const& name, shared_ptr< formatte
BOOST_ASSERT(!!factory);
formatters_repository< CharT >& repo = formatters_repository< CharT >::get();
BOOST_LOG_EXPR_IF_MT(log::aux::exclusive_lock_guard< log::aux::light_rw_mutex > _(repo.m_Mutex);)
BOOST_LOG_EXPR_IF_MT(log::aux::exclusive_lock_guard< log::aux::light_rw_mutex > lock(repo.m_Mutex);)
repo.m_Map[name] = factory;
}
@@ -393,21 +425,15 @@ basic_formatter< CharT > parse_formatter(const CharT* begin, const CharT* end)
{
typedef CharT char_type;
formatter_grammar< char_type > gram;
formatter_parser< char_type > parser;
const char_type* p = begin;
BOOST_LOG_EXPR_IF_MT(formatters_repository< CharT >& repo = formatters_repository< CharT >::get();)
BOOST_LOG_EXPR_IF_MT(log::aux::shared_lock_guard< log::aux::light_rw_mutex > _(repo.m_Mutex);)
BOOST_LOG_EXPR_IF_MT(log::aux::shared_lock_guard< log::aux::light_rw_mutex > lock(repo.m_Mutex);)
bool result = qi::parse(p, end, gram);
if (!result || p != end)
{
std::ostringstream strm;
strm << "Could not parse the formatter, parsing stopped at position " << p - begin;
BOOST_LOG_THROW_DESCR(parse_error, strm.str());
}
parser.parse(p, end);
return gram.get_formatter();
return parser.get_formatter();
}
#ifdef BOOST_LOG_USE_CHAR