1/*
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)
6 */
7/*!
8 * \file settings_parser.cpp
9 * \author Andrey Semashev
10 * \date 20.07.2012
11 *
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.
14 */
15
16#include <boost/log/detail/setup_config.hpp>
17
18#ifndef BOOST_LOG_WITHOUT_SETTINGS_PARSERS
19
20#include <string>
21#include <locale>
22#include <iostream>
23#include <stdexcept>
24#include <algorithm>
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>
38
39namespace boost {
40
41BOOST_LOG_OPEN_NAMESPACE
42
43BOOST_LOG_ANONYMOUS_NAMESPACE {
44
45//! Settings parser
46template< typename CharT >
47class settings_parser
48{
49private:
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;
54
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;
58
59private:
60 //! Current section name
61 std::string m_SectionName;
62 //! Current parameter name
63 std::string m_ParameterName;
64 //! Settings instance
65 settings_type& m_Settings;
66 //! Locale from the source stream
67 std::locale m_Locale;
68 //! Current line number
69 unsigned int& m_LineCounter;
70
71public:
72 //! Constructor
73 explicit settings_parser(settings_type& setts, unsigned int& line_counter, std::locale const& loc) :
74 m_Settings(setts),
75 m_Locale(loc),
76 m_LineCounter(line_counter)
77 {
78 }
79
80 //! Parses a line of the input
81 void parse_line(iterator_type& begin, iterator_type end)
82 {
83 iterator_type p = begin;
84 p = constants::trim_spaces_left(p, end);
85 if (p != end)
86 {
87 char_type c = *p;
88 if (c == constants::char_section_bracket_left)
89 {
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);
94 if (stop == end)
95 BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Section header is invalid", (m_LineCounter));
96
97 p = stop + 1;
98 stop = constants::trim_spaces_right(start, stop);
99
100 set_section_name(begin: start, end: stop);
101 }
102 else if (c != constants::char_comment)
103 {
104 // We have a parameter
105 iterator_type eq = std::find(p, end, constants::char_equal);
106 if (eq == end)
107 BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Parameter description is invalid", (m_LineCounter));
108
109 // Parameter name
110 set_parameter_name(begin: p, end: constants::trim_spaces_right(p, eq));
111
112 // Parameter value
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));
116
117 try
118 {
119 string_type value;
120 p = constants::parse_operand(p, end, value);
121 set_parameter_value(value);
122 }
123 catch (parse_error& e)
124 {
125 throw boost::enable_error_info(x: e) << boost::errinfo_at_line(m_LineCounter);
126 }
127 }
128
129 // In the end of the line we may have a comment
130 p = constants::trim_spaces_left(p, end);
131 if (p != end)
132 {
133 c = *p;
134 if (c == constants::char_comment)
135 {
136 // The comment spans until the end of the line
137 p = end;
138 }
139 else
140 {
141 BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Unexpected characters in the end of the line", (m_LineCounter));
142 }
143 }
144 }
145
146 begin = p;
147 }
148
149private:
150 //! The method sets the parsed section name
151 void set_section_name(iterator_type begin, iterator_type end)
152 {
153 // Check that the section name is valid
154 if (begin == end)
155 BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Section name is empty", (m_LineCounter));
156
157 for (iterator_type p = begin; p != end; ++p)
158 {
159 char_type c = *p;
160 if (c != constants::char_dot && !encoding::isalnum(c))
161 BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Section name is invalid", (m_LineCounter));
162 }
163
164 m_SectionName = log::aux::to_narrow(string_type(begin, end), m_Locale);
165
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(pos: 0, n1: 5, s: "Sink:") == 0)
169 m_SectionName = "Sinks." + m_SectionName.substr(pos: 5);
170 }
171
172 //! The method sets the parsed parameter name
173 void set_parameter_name(iterator_type begin, iterator_type end)
174 {
175 if (m_SectionName.empty())
176 {
177 // The parameter encountered before any section starter
178 BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Parameters are only allowed within sections", (m_LineCounter));
179 }
180
181 // Check that the parameter name is valid
182 if (begin == end)
183 BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Parameter name is empty", (m_LineCounter));
184
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)
189 {
190 char_type c = *p;
191 if (!encoding::isgraph(c))
192 BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Parameter name is invalid", (m_LineCounter));
193 }
194
195 m_ParameterName = log::aux::to_narrow(string_type(begin, end), m_Locale);
196 }
197
198 //! The method sets the parsed parameter value (non-quoted)
199 void set_parameter_value(string_type const& value)
200 {
201 m_Settings[m_SectionName][m_ParameterName] = value;
202 m_ParameterName.clear();
203 }
204
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&))
208};
209
210} // namespace
211
212//! The function parses library settings from an input stream
213template< typename CharT >
214BOOST_LOG_SETUP_API basic_settings< CharT > parse_settings(std::basic_istream< CharT >& strm)
215{
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;
220
221 if (!strm.good())
222 BOOST_THROW_EXCEPTION(std::invalid_argument("The input stream for parsing settings is not valid"));
223
224 io::basic_ios_exception_saver< char_type > exceptions_guard(strm, std::ios_base::badbit);
225
226 // Engage parsing
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);
231
232 string_type line;
233 while (!strm.eof())
234 {
235 std::getline(strm, line);
236
237 const char_type* p = line.c_str();
238 parser.parse_line(p, p + line.size());
239
240 line.clear();
241 ++line_number;
242 }
243
244 return BOOST_LOG_NRVO_RESULT(settings);
245}
246
247
248#ifdef BOOST_LOG_USE_CHAR
249template BOOST_LOG_SETUP_API basic_settings< char > parse_settings< char >(std::basic_istream< char >& strm);
250#endif
251#ifdef BOOST_LOG_USE_WCHAR_T
252template BOOST_LOG_SETUP_API basic_settings< wchar_t > parse_settings< wchar_t >(std::basic_istream< wchar_t >& strm);
253#endif
254
255BOOST_LOG_CLOSE_NAMESPACE // namespace log
256
257} // namespace boost
258
259#include <boost/log/detail/footer.hpp>
260
261#endif // BOOST_LOG_WITHOUT_SETTINGS_PARSERS
262

source code of boost/libs/log/src/setup/settings_parser.cpp