]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/log/src/setup/formatter_parser.cpp
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / boost / libs / log / src / setup / formatter_parser.cpp
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 formatter_parser.cpp
9 * \author Andrey Semashev
10 * \date 07.04.2008
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 #ifndef BOOST_LOG_WITHOUT_SETTINGS_PARSERS
17
18 #include <boost/log/detail/setup_config.hpp>
19 #include <map>
20 #include <string>
21 #include <sstream>
22 #include <stdexcept>
23 #include <boost/assert.hpp>
24 #include <boost/bind.hpp>
25 #include <boost/move/core.hpp>
26 #include <boost/move/utility_core.hpp>
27 #include <boost/optional/optional.hpp>
28 #include <boost/utility/in_place_factory.hpp>
29 #include <boost/log/expressions/formatter.hpp>
30 #include <boost/log/attributes/attribute_name.hpp>
31 #include <boost/log/exceptions.hpp>
32 #include <boost/log/detail/singleton.hpp>
33 #include <boost/log/detail/code_conversion.hpp>
34 #include <boost/log/detail/default_attribute_names.hpp>
35 #include <boost/log/utility/formatting_ostream.hpp>
36 #include <boost/log/utility/functional/nop.hpp>
37 #include <boost/log/utility/setup/formatter_parser.hpp>
38 #if !defined(BOOST_LOG_NO_THREADS)
39 #include <boost/log/detail/locks.hpp>
40 #include <boost/log/detail/light_rw_mutex.hpp>
41 #endif
42 #include "parser_utils.hpp"
43 #include "spirit_encoding.hpp"
44 #if !defined(BOOST_LOG_WITHOUT_DEFAULT_FACTORIES)
45 #include "default_formatter_factory.hpp"
46 #endif
47 #include <boost/log/detail/header.hpp>
48
49 namespace boost {
50
51 BOOST_LOG_OPEN_NAMESPACE
52
53 BOOST_LOG_ANONYMOUS_NAMESPACE {
54
55 //! The structure contains formatter factories repository
56 template< typename CharT >
57 struct formatters_repository :
58 public log::aux::lazy_singleton< formatters_repository< CharT > >
59 {
60 //! Base class type
61 typedef log::aux::lazy_singleton< formatters_repository< CharT > > base_type;
62
63 #if !defined(BOOST_LOG_BROKEN_FRIEND_TEMPLATE_SPECIALIZATIONS)
64 friend class log::aux::lazy_singleton< formatters_repository< CharT > >;
65 #else
66 friend class base_type;
67 #endif
68
69 typedef CharT char_type;
70 typedef formatter_factory< char_type > formatter_factory_type;
71
72 //! Attribute name ordering predicate
73 struct attribute_name_order
74 {
75 typedef bool result_type;
76 result_type operator() (attribute_name const& left, attribute_name const& right) const
77 {
78 return left.id() < right.id();
79 }
80 };
81
82 //! Map of formatter factories
83 typedef std::map< attribute_name, shared_ptr< formatter_factory_type >, attribute_name_order > factories_map;
84
85
86 #if !defined(BOOST_LOG_NO_THREADS)
87 //! Synchronization mutex
88 mutable log::aux::light_rw_mutex m_Mutex;
89 #endif
90 //! The map of formatter factories
91 factories_map m_Map;
92 #if !defined(BOOST_LOG_WITHOUT_DEFAULT_FACTORIES)
93 //! Default factory
94 mutable aux::default_formatter_factory< char_type > m_DefaultFactory;
95 #endif
96
97 //! The method returns the filter factory for the specified attribute name
98 formatter_factory_type& get_factory(attribute_name const& name) const
99 {
100 typename factories_map::const_iterator it = m_Map.find(name);
101 if (it != m_Map.end())
102 {
103 return *it->second;
104 }
105 else
106 {
107 #if !defined(BOOST_LOG_WITHOUT_DEFAULT_FACTORIES)
108 return m_DefaultFactory;
109 #else
110 BOOST_LOG_THROW_DESCR(setup_error, "No formatter factory registered for attribute " + name.string());
111 #endif
112 }
113 }
114
115 private:
116 formatters_repository()
117 {
118 }
119 };
120
121 //! Function object for formatter chaining
122 template< typename CharT, typename SecondT >
123 struct chained_formatter
124 {
125 typedef void result_type;
126 typedef basic_formatter< CharT > formatter_type;
127 typedef typename formatter_type::stream_type stream_type;
128
129 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
130 explicit chained_formatter(formatter_type&& first, SecondT&& second) :
131 #else
132 template< typename T >
133 explicit chained_formatter(BOOST_RV_REF(formatter_type) first, T const& second) :
134 #endif
135 m_first(boost::move(first)), m_second(boost::move(second))
136 {
137 }
138
139 result_type operator() (record_view const& rec, stream_type& strm) const
140 {
141 m_first(rec, strm);
142 m_second(rec, strm);
143 }
144
145 private:
146 formatter_type m_first;
147 SecondT m_second;
148 };
149
150 //! String literal formatter
151 template< typename CharT >
152 struct literal_formatter
153 {
154 typedef void result_type;
155 typedef CharT char_type;
156 typedef std::basic_string< char_type > string_type;
157 typedef basic_formatting_ostream< char_type > stream_type;
158
159 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
160 explicit literal_formatter(string_type&& str) : m_str(boost::move(str))
161 #else
162 explicit literal_formatter(string_type const& str) : m_str(str)
163 #endif
164 {
165 }
166
167 result_type operator() (record_view const& rec, stream_type& strm) const
168 {
169 strm << m_str;
170 }
171
172 private:
173 const string_type m_str;
174 };
175
176 //! Formatter parsing grammar
177 template< typename CharT >
178 class formatter_parser
179 {
180 private:
181 typedef CharT char_type;
182 typedef const char_type* iterator_type;
183 typedef std::basic_string< char_type > string_type;
184 typedef basic_formatter< char_type > formatter_type;
185 typedef boost::log::aux::char_constants< char_type > constants;
186 typedef typename log::aux::encoding< char_type >::type encoding;
187 typedef log::aux::encoding_specific< encoding > encoding_specific;
188 typedef formatter_factory< char_type > formatter_factory_type;
189 typedef typename formatter_factory_type::args_map args_map;
190
191 private:
192 //! The formatter being constructed
193 optional< formatter_type > m_Formatter;
194
195 //! Attribute name
196 attribute_name m_AttrName;
197 //! Formatter factory arguments
198 args_map m_FactoryArgs;
199
200 //! Formatter argument name
201 mutable string_type m_ArgName;
202 //! Argument value
203 mutable string_type m_ArgValue;
204
205 public:
206 //! Constructor
207 formatter_parser()
208 {
209 }
210
211 //! Parses formatter
212 void parse(iterator_type& begin, iterator_type end)
213 {
214 iterator_type p = begin;
215
216 while (p != end)
217 {
218 // Find the end of a string literal
219 iterator_type start = p;
220 for (; p != end; ++p)
221 {
222 char_type c = *p;
223 if (c == constants::char_backslash)
224 {
225 // We found an escaped character
226 ++p;
227 if (p == end)
228 BOOST_LOG_THROW_DESCR(parse_error, "Invalid escape sequence in the formatter string");
229 }
230 else if (c == constants::char_percent)
231 {
232 // We found an attribute
233 break;
234 }
235 }
236
237 if (start != p)
238 push_string(start, p);
239
240 if (p != end)
241 {
242 // We found an attribute placeholder
243 iterator_type start = constants::trim_spaces_left(++p, end);
244 p = constants::scan_attr_placeholder(start, end);
245 if (p == end)
246 BOOST_LOG_THROW_DESCR(parse_error, "Invalid attribute placeholder in the formatter string");
247
248 on_attribute_name(start, p);
249
250 p = constants::trim_spaces_left(p, end);
251 if (p == end)
252 BOOST_LOG_THROW_DESCR(parse_error, "Invalid attribute placeholder in the formatter string");
253
254 if (*p == constants::char_paren_bracket_left)
255 {
256 // We found formatter arguments
257 p = parse_args(constants::trim_spaces_left(++p, end), end);
258 p = constants::trim_spaces_left(p, end);
259 if (p == end)
260 BOOST_LOG_THROW_DESCR(parse_error, "Invalid attribute placeholder in the formatter string");
261 }
262
263 if (*p != constants::char_percent)
264 BOOST_LOG_THROW_DESCR(parse_error, "Invalid attribute placeholder in the formatter string");
265
266 ++p;
267
268 push_attr();
269 }
270 }
271
272 begin = p;
273 }
274
275 //! Returns the parsed formatter
276 formatter_type get_formatter()
277 {
278 if (!m_Formatter)
279 {
280 // This may happen if parser input is an empty string
281 return formatter_type(nop());
282 }
283
284 return boost::move(m_Formatter.get());
285 }
286
287 private:
288 //! The method parses formatter arguments
289 iterator_type parse_args(iterator_type begin, iterator_type end)
290 {
291 iterator_type p = begin;
292 if (p == end)
293 BOOST_LOG_THROW_DESCR(parse_error, "Invalid attribute placeholder arguments description in the formatter string");
294 if (*p == constants::char_paren_bracket_right)
295 return ++p;
296
297 while (true)
298 {
299 char_type c = *p;
300
301 // Read argument name
302 iterator_type start = p;
303 if (!encoding::isalpha(*p))
304 BOOST_LOG_THROW_DESCR(parse_error, "Placeholder argument name is invalid");
305 for (++p; p != end; ++p)
306 {
307 c = *p;
308 if (encoding::isspace(c) || c == constants::char_equal)
309 break;
310 if (!encoding::isalnum(c) && c != constants::char_underline)
311 BOOST_LOG_THROW_DESCR(parse_error, "Placeholder argument name is invalid");
312 }
313
314 if (start == p)
315 BOOST_LOG_THROW_DESCR(parse_error, "Placeholder argument name is empty");
316
317 on_arg_name(start, p);
318
319 p = constants::trim_spaces_left(p, end);
320 if (p == end || *p != constants::char_equal)
321 BOOST_LOG_THROW_DESCR(parse_error, "Placeholder argument description is not valid");
322
323 // Read argument value
324 start = p = constants::trim_spaces_left(++p, end);
325 p = constants::parse_operand(p, end, m_ArgValue);
326 if (p == start)
327 BOOST_LOG_THROW_DESCR(parse_error, "Placeholder argument value is not specified");
328
329 push_arg();
330
331 p = constants::trim_spaces_left(p, end);
332 if (p == end)
333 BOOST_LOG_THROW_DESCR(parse_error, "Invalid attribute placeholder arguments description in the formatter string");
334
335 c = *p;
336 if (c == constants::char_paren_bracket_right)
337 {
338 break;
339 }
340 else if (c == constants::char_comma)
341 {
342 p = constants::trim_spaces_left(++p, end);
343 if (p == end)
344 BOOST_LOG_THROW_DESCR(parse_error, "Placeholder argument name is invalid");
345 }
346 else
347 {
348 BOOST_LOG_THROW_DESCR(parse_error, "Invalid attribute placeholder arguments description in the formatter string");
349 }
350 }
351
352 return ++p;
353 }
354
355 //! The method is called when an argument name is discovered
356 void on_arg_name(iterator_type begin, iterator_type end)
357 {
358 m_ArgName.assign(begin, end);
359 }
360
361 //! The method is called when an argument is filled
362 void push_arg()
363 {
364 m_FactoryArgs[m_ArgName] = m_ArgValue;
365 m_ArgName.clear();
366 m_ArgValue.clear();
367 }
368
369 //! The method is called when an attribute name is discovered
370 void on_attribute_name(iterator_type begin, iterator_type end)
371 {
372 if (begin == end)
373 BOOST_LOG_THROW_DESCR(parse_error, "Empty attribute name encountered");
374
375 // For compatibility with Boost.Log v1 we recognize %_% as the message attribute name
376 const std::size_t len = end - begin;
377 if (std::char_traits< char_type >::length(constants::message_text_keyword()) == len &&
378 std::char_traits< char_type >::compare(constants::message_text_keyword(), begin, len) == 0)
379 {
380 m_AttrName = log::aux::default_attribute_names::message();
381 }
382 else
383 {
384 m_AttrName = attribute_name(log::aux::to_narrow(string_type(begin, end)));
385 }
386 }
387 //! The method is called when an attribute is filled
388 void push_attr()
389 {
390 BOOST_ASSERT_MSG(!!m_AttrName, "Attribute name is not set");
391
392 if (m_AttrName == log::aux::default_attribute_names::message())
393 {
394 // We make a special treatment for the message text formatter
395 append_formatter(expressions::aux::message_formatter());
396 }
397 else
398 {
399 // Use the factory to create the formatter
400 formatters_repository< char_type > const& repo = formatters_repository< char_type >::get();
401 formatter_factory_type& factory = repo.get_factory(m_AttrName);
402 append_formatter(factory.create_formatter(m_AttrName, m_FactoryArgs));
403 }
404
405 // Eventually, clear all the auxiliary data
406 m_AttrName = attribute_name();
407 m_FactoryArgs.clear();
408 }
409
410 //! The method is called when a string literal is discovered
411 void push_string(iterator_type begin, iterator_type end)
412 {
413 string_type s(begin, end);
414 constants::translate_escape_sequences(s);
415 append_formatter(literal_formatter< char_type >(boost::move(s)));
416 }
417
418 //! The method appends a formatter part to the final formatter
419 template< typename FormatterT >
420 void append_formatter(FormatterT fmt)
421 {
422 if (!!m_Formatter)
423 m_Formatter = boost::in_place(chained_formatter< char_type, FormatterT >(boost::move(m_Formatter.get()), boost::move(fmt)));
424 else
425 m_Formatter = boost::in_place(boost::move(fmt));
426 }
427
428 // Assignment and copying are prohibited
429 BOOST_DELETED_FUNCTION(formatter_parser(formatter_parser const&))
430 BOOST_DELETED_FUNCTION(formatter_parser& operator= (formatter_parser const&))
431 };
432
433 } // namespace
434
435 //! The function registers a user-defined formatter factory
436 template< typename CharT >
437 BOOST_LOG_SETUP_API void register_formatter_factory(attribute_name const& name, shared_ptr< formatter_factory< CharT > > const& factory)
438 {
439 BOOST_ASSERT(!!name);
440 BOOST_ASSERT(!!factory);
441
442 formatters_repository< CharT >& repo = formatters_repository< CharT >::get();
443 BOOST_LOG_EXPR_IF_MT(log::aux::exclusive_lock_guard< log::aux::light_rw_mutex > lock(repo.m_Mutex);)
444 repo.m_Map[name] = factory;
445 }
446
447 //! The function parses a formatter from the string
448 template< typename CharT >
449 BOOST_LOG_SETUP_API basic_formatter< CharT > parse_formatter(const CharT* begin, const CharT* end)
450 {
451 typedef CharT char_type;
452
453 formatter_parser< char_type > parser;
454 const char_type* p = begin;
455
456 BOOST_LOG_EXPR_IF_MT(formatters_repository< CharT >& repo = formatters_repository< CharT >::get();)
457 BOOST_LOG_EXPR_IF_MT(log::aux::shared_lock_guard< log::aux::light_rw_mutex > lock(repo.m_Mutex);)
458
459 parser.parse(p, end);
460
461 return parser.get_formatter();
462 }
463
464 #ifdef BOOST_LOG_USE_CHAR
465 template BOOST_LOG_SETUP_API
466 void register_formatter_factory< char >(
467 attribute_name const& attr_name, shared_ptr< formatter_factory< char > > const& factory);
468 template BOOST_LOG_SETUP_API
469 basic_formatter< char > parse_formatter< char >(const char* begin, const char* end);
470 #endif // BOOST_LOG_USE_CHAR
471
472 #ifdef BOOST_LOG_USE_WCHAR_T
473 template BOOST_LOG_SETUP_API
474 void register_formatter_factory< wchar_t >(
475 attribute_name const& attr_name, shared_ptr< formatter_factory< wchar_t > > const& factory);
476 template BOOST_LOG_SETUP_API
477 basic_formatter< wchar_t > parse_formatter< wchar_t >(const wchar_t* begin, const wchar_t* end);
478 #endif // BOOST_LOG_USE_WCHAR_T
479
480 BOOST_LOG_CLOSE_NAMESPACE // namespace log
481
482 } // namespace boost
483
484 #include <boost/log/detail/footer.hpp>
485
486 #endif // BOOST_LOG_WITHOUT_SETTINGS_PARSERS