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 settings_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/setup_config.hpp>
18 #ifndef BOOST_LOG_WITHOUT_SETTINGS_PARSERS
25 #include <boost/throw_exception.hpp>
26 #include <boost/exception/exception.hpp>
27 #include <boost/exception/info.hpp>
28 #include <boost/exception/errinfo_at_line.hpp>
29 #include <boost/io/ios_state.hpp>
30 #include <boost/move/core.hpp>
31 #include <boost/move/utility_core.hpp>
32 #include <boost/log/detail/code_conversion.hpp>
33 #include <boost/log/utility/setup/settings_parser.hpp>
34 #include <boost/log/exceptions.hpp>
35 #include "parser_utils.hpp"
36 #include "spirit_encoding.hpp"
37 #include <boost/log/detail/header.hpp>
41 BOOST_LOG_OPEN_NAMESPACE
43 BOOST_LOG_ANONYMOUS_NAMESPACE
{
46 template< typename CharT
>
50 typedef CharT char_type
;
51 typedef const char_type
* iterator_type
;
52 typedef typename
log::aux::encoding
< char_type
>::type encoding
;
53 typedef settings_parser
< char_type
> this_type
;
55 typedef std::basic_string
< char_type
> string_type
;
56 typedef log::aux::char_constants
< char_type
> constants
;
57 typedef basic_settings
< char_type
> settings_type
;
60 //! Current section name
61 std::string m_SectionName
;
62 //! Current parameter name
63 std::string m_ParameterName
;
65 settings_type
& m_Settings
;
66 //! Locale from the source stream
68 //! Current line number
69 unsigned int& m_LineCounter
;
73 explicit settings_parser(settings_type
& setts
, unsigned int& line_counter
, std::locale
const& loc
) :
76 m_LineCounter(line_counter
)
80 //! Parses a line of the input
81 void parse_line(iterator_type
& begin
, iterator_type end
)
83 iterator_type p
= begin
;
84 p
= constants::trim_spaces_left(p
, end
);
88 if (c
== constants::char_section_bracket_left
)
90 // We have a section name
91 iterator_type start
= ++p
;
92 start
= constants::trim_spaces_left(start
, end
);
93 iterator_type stop
= std::find(start
, end
, constants::char_section_bracket_right
);
95 BOOST_LOG_THROW_DESCR_PARAMS(parse_error
, "Section header is invalid", (m_LineCounter
));
98 stop
= constants::trim_spaces_right(start
, stop
);
100 set_section_name(start
, stop
);
102 else if (c
!= constants::char_comment
)
104 // We have a parameter
105 iterator_type eq
= std::find(p
, end
, constants::char_equal
);
107 BOOST_LOG_THROW_DESCR_PARAMS(parse_error
, "Parameter description is invalid", (m_LineCounter
));
110 set_parameter_name(p
, constants::trim_spaces_right(p
, eq
));
113 p
= constants::trim_spaces_left(eq
+ 1, end
);
114 if (p
== end
|| *p
== constants::char_comment
)
115 BOOST_LOG_THROW_DESCR_PARAMS(parse_error
, "Parameter value is not specified", (m_LineCounter
));
120 p
= constants::parse_operand(p
, end
, value
);
121 set_parameter_value(value
);
123 catch (parse_error
& e
)
125 throw boost::enable_error_info(e
) << boost::errinfo_at_line(m_LineCounter
);
129 // In the end of the line we may have a comment
130 p
= constants::trim_spaces_left(p
, end
);
134 if (c
== constants::char_comment
)
136 // The comment spans until the end of the line
141 BOOST_LOG_THROW_DESCR_PARAMS(parse_error
, "Unexpected characters in the end of the line", (m_LineCounter
));
150 //! The method sets the parsed section name
151 void set_section_name(iterator_type begin
, iterator_type end
)
153 // Check that the section name is valid
155 BOOST_LOG_THROW_DESCR_PARAMS(parse_error
, "Section name is empty", (m_LineCounter
));
157 for (iterator_type p
= begin
; p
!= end
; ++p
)
160 if (c
!= constants::char_dot
&& !encoding::isalnum(c
))
161 BOOST_LOG_THROW_DESCR_PARAMS(parse_error
, "Section name is invalid", (m_LineCounter
));
164 m_SectionName
= log::aux::to_narrow(string_type(begin
, end
), m_Locale
);
166 // For compatibility with Boost.Log v1, we replace the "Sink:" prefix with "Sinks."
167 // so that all sink parameters are placed in the common Sinks section.
168 if (m_SectionName
.compare(0, 5, "Sink:") == 0)
169 m_SectionName
= "Sinks." + m_SectionName
.substr(5);
172 //! The method sets the parsed parameter name
173 void set_parameter_name(iterator_type begin
, iterator_type end
)
175 if (m_SectionName
.empty())
177 // The parameter encountered before any section starter
178 BOOST_LOG_THROW_DESCR_PARAMS(parse_error
, "Parameters are only allowed within sections", (m_LineCounter
));
181 // Check that the parameter name is valid
183 BOOST_LOG_THROW_DESCR_PARAMS(parse_error
, "Parameter name is empty", (m_LineCounter
));
185 iterator_type p
= begin
;
186 if (!encoding::isalpha(*p
))
187 BOOST_LOG_THROW_DESCR_PARAMS(parse_error
, "Parameter name is invalid", (m_LineCounter
));
188 for (++p
; p
!= end
; ++p
)
191 if (!encoding::isgraph(c
))
192 BOOST_LOG_THROW_DESCR_PARAMS(parse_error
, "Parameter name is invalid", (m_LineCounter
));
195 m_ParameterName
= log::aux::to_narrow(string_type(begin
, end
), m_Locale
);
198 //! The method sets the parsed parameter value (non-quoted)
199 void set_parameter_value(string_type
const& value
)
201 m_Settings
[m_SectionName
][m_ParameterName
] = value
;
202 m_ParameterName
.clear();
205 // Assignment and copying are prohibited
206 BOOST_DELETED_FUNCTION(settings_parser(settings_parser
const&))
207 BOOST_DELETED_FUNCTION(settings_parser
& operator= (settings_parser
const&))
212 //! The function parses library settings from an input stream
213 template< typename CharT
>
214 BOOST_LOG_SETUP_API basic_settings
< CharT
> parse_settings(std::basic_istream
< CharT
>& strm
)
216 typedef CharT char_type
;
217 typedef std::basic_string
< char_type
> string_type
;
218 typedef settings_parser
< char_type
> settings_parser_type
;
219 typedef basic_settings
< char_type
> settings_type
;
222 BOOST_THROW_EXCEPTION(std::invalid_argument("The input stream for parsing settings is not valid"));
224 io::basic_ios_exception_saver
< char_type
> exceptions_guard(strm
, std::ios_base::badbit
);
227 settings_type settings
;
228 unsigned int line_number
= 1;
229 std::locale loc
= strm
.getloc();
230 settings_parser_type
parser(settings
, line_number
, loc
);
235 std::getline(strm
, line
);
237 const char_type
* p
= line
.c_str();
238 parser
.parse_line(p
, p
+ line
.size());
244 return BOOST_LOG_NRVO_RESULT(settings
);
248 #ifdef BOOST_LOG_USE_CHAR
249 template BOOST_LOG_SETUP_API basic_settings
< char > parse_settings
< char >(std::basic_istream
< char >& strm
);
251 #ifdef BOOST_LOG_USE_WCHAR_T
252 template BOOST_LOG_SETUP_API basic_settings
< wchar_t > parse_settings
< wchar_t >(std::basic_istream
< wchar_t >& strm
);
255 BOOST_LOG_CLOSE_NAMESPACE
// namespace log
259 #include <boost/log/detail/footer.hpp>
261 #else // BOOST_LOG_WITHOUT_SETTINGS_PARSERS
263 #include <boost/log/detail/header.hpp>
267 BOOST_LOG_OPEN_NAMESPACE
269 BOOST_LOG_SETUP_API
void boost_log_setup_is_empty()
271 // This dummy export exists to that boost_log_setup library is not empty and is created even if settings parsers are disabled.
272 // MSVC is known to not generate the library if it contains no exports (https://github.com/boostorg/log/issues/164), which breaks
273 // install targets as Boost.Build cannot find the library file to install.
274 // We use this dummy export instead of disabling building boost_log_setup in the first place because of this Boost.Build bug:
276 // https://github.com/bfgroup/b2/issues/104
278 // After this bug is fixed, we can consider removing this dummy export and disabling building the library proper.
281 BOOST_LOG_CLOSE_NAMESPACE
// namespace log
285 #include <boost/log/detail/footer.hpp>
287 #endif // BOOST_LOG_WITHOUT_SETTINGS_PARSERS