2 * Copyright Andrey Semashev 2007 - 2015.
3 * Distributed under the Boost Software License, Version 1.0.
4 * (See accompanying file LICENSE_1_0.txt or copy at
5 * http://www.boost.org/LICENSE_1_0.txt)
8 * \file format_parser.cpp
9 * \author Andrey Semashev
12 * \brief This header is the Boost.Log library implementation, see the library documentation
13 * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
16 #include <boost/log/detail/config.hpp>
19 #include <boost/throw_exception.hpp>
20 #include <boost/exception/exception.hpp>
21 #include <boost/move/core.hpp>
22 #include <boost/move/utility_core.hpp>
23 #include <boost/spirit/include/qi_uint.hpp>
24 #include <boost/spirit/include/qi_parse.hpp>
25 #include <boost/log/detail/format.hpp>
26 #include <boost/log/exceptions.hpp>
27 #include <boost/log/support/exception.hpp>
28 #include "spirit_encoding.hpp"
29 #include <boost/log/detail/header.hpp>
31 namespace qi
= boost::spirit::qi
;
35 BOOST_LOG_OPEN_NAMESPACE
39 template< typename CharT
>
40 BOOST_LOG_API format_description
< CharT
> parse_format(const CharT
* begin
, const CharT
* end
)
42 typedef CharT char_type
;
43 typedef format_description
< char_type
> description
;
44 typedef typename encoding
< char_type
>::type traits
;
46 const char_type
* original_begin
= begin
;
48 unsigned int literal_start_pos
= 0;
52 const char_type
* p
= std::find(begin
, end
, static_cast< char_type
>('%'));
53 descr
.literal_chars
.append(begin
, p
);
57 // Check for a percent placeholder
59 if (c
== static_cast< char_type
>('%'))
61 descr
.literal_chars
.push_back(static_cast< char_type
>('%'));
66 // From here on, no more literals are possible. Append the literal element.
68 const unsigned int literal_chars_size
= static_cast< unsigned int >(descr
.literal_chars
.size());
69 if (literal_start_pos
< literal_chars_size
)
71 descr
.format_elements
.push_back(format_element::literal(literal_start_pos
, literal_chars_size
- literal_start_pos
));
72 literal_start_pos
= literal_chars_size
;
76 // Check if this is a positional argument
77 if (traits::isdigit(c
))
79 if (c
!= static_cast< char_type
>('0'))
81 // Positional argument in the form "%N%"
83 const char_type
* pp
= p
+ 1;
84 qi::parse(pp
, end
, qi::uint_
, n
);
85 if (n
== 0 || pp
== end
|| *pp
!= static_cast< char_type
>('%'))
87 boost::throw_exception(boost::enable_error_info(parse_error("Invalid positional format placeholder")) << boost::throw_file(__FILE__
) << boost::throw_line(__LINE__
)
88 << boost::log::position_info(static_cast< unsigned int >(p
- original_begin
))
92 // Safety check against ridiculously large argument numbers which would lead to excessive memory consumption.
93 // This could be useful if the format string is gathered from an external source (e.g. a config file).
96 boost::throw_exception(boost::enable_error_info(limitation_error("Positional format placeholder too big")) << boost::throw_file(__FILE__
) << boost::throw_line(__LINE__
)
97 << boost::log::position_info(static_cast< unsigned int >(p
- original_begin
))
101 // We count positional arguments from 0, not from 1 as in format strings
102 descr
.format_elements
.push_back(format_element::positional_argument(n
- 1));
103 begin
= pp
+ 1; // skip the closing '%'
109 // This must be the filler character, not supported yet
113 // This must be something else, not supported yet
114 boost::throw_exception(boost::enable_error_info(parse_error("Unsupported format placeholder")) << boost::throw_file(__FILE__
) << boost::throw_line(__LINE__
)
115 << boost::log::position_info(static_cast< unsigned int >(p
- original_begin
))
121 descr
.literal_chars
.push_back(static_cast< char_type
>('%')); // a single '%' character at the end of the string
126 const unsigned int literal_chars_size
= static_cast< unsigned int >(descr
.literal_chars
.size());
127 if (literal_start_pos
< literal_chars_size
)
128 descr
.format_elements
.push_back(format_element::literal(literal_start_pos
, literal_chars_size
- literal_start_pos
));
130 return BOOST_LOG_NRVO_RESULT(descr
);
134 #ifdef BOOST_LOG_USE_CHAR
136 template BOOST_LOG_API
137 format_description
< char > parse_format(const char* begin
, const char* end
);
139 #endif // BOOST_LOG_USE_CHAR
141 #ifdef BOOST_LOG_USE_WCHAR_T
143 template BOOST_LOG_API
144 format_description
< wchar_t > parse_format(const wchar_t* begin
, const wchar_t* end
);
146 #endif // BOOST_LOG_USE_WCHAR_T
150 BOOST_LOG_CLOSE_NAMESPACE
// namespace log
154 #include <boost/log/detail/footer.hpp>