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   filter_parser.hpp
9  * \author Andrey Semashev
10  * \date   31.03.2008
11  *
12  * The header contains definition of a filter parser function.
13  */
14 
15 #ifndef BOOST_LOG_UTILITY_SETUP_FILTER_PARSER_HPP_INCLUDED_
16 #define BOOST_LOG_UTILITY_SETUP_FILTER_PARSER_HPP_INCLUDED_
17 
18 #include <string>
19 #include <boost/lexical_cast.hpp>
20 #include <boost/smart_ptr/shared_ptr.hpp>
21 #include <boost/smart_ptr/make_shared_object.hpp>
22 #include <boost/phoenix/operator/comparison.hpp>
23 #include <boost/type_traits/is_base_and_derived.hpp>
24 #include <boost/core/enable_if.hpp>
25 #include <boost/log/detail/setup_config.hpp>
26 #include <boost/log/detail/code_conversion.hpp>
27 #include <boost/log/exceptions.hpp>
28 #include <boost/log/attributes/attribute_name.hpp>
29 #include <boost/log/attributes/attribute_value_set.hpp>
30 #include <boost/log/expressions/filter.hpp>
31 #include <boost/log/expressions/keyword_fwd.hpp>
32 #include <boost/log/expressions/attr.hpp>
33 #include <boost/log/expressions/predicates/has_attr.hpp>
34 #include <boost/log/core/core.hpp>
35 #include <boost/log/detail/header.hpp>
36 
37 #ifdef BOOST_HAS_PRAGMA_ONCE
38 #pragma once
39 #endif
40 
41 namespace boost {
42 
43 BOOST_LOG_OPEN_NAMESPACE
44 
45 /*!
46  * The interface class for all filter factories.
47  */
48 template< typename CharT >
49 struct filter_factory
50 {
51     //! Character type
52     typedef CharT char_type;
53     //! String type
54     typedef std::basic_string< char_type > string_type;
55 
56     /*!
57      * Default constructor
58      */
filter_factoryboost::filter_factory59     BOOST_DEFAULTED_FUNCTION(filter_factory(), {})
60 
61     /*!
62      * Virtual destructor
63      */
64     virtual ~filter_factory() {}
65 
66     /*!
67      * The callback for filter for the attribute existence test
68      */
on_exists_testboost::filter_factory69     virtual filter on_exists_test(attribute_name const& name)
70     {
71         return filter(expressions::has_attr(name));
72     }
73 
74     /*!
75      * The callback for equality relation filter
76      */
on_equality_relationboost::filter_factory77     virtual filter on_equality_relation(attribute_name const& name, string_type const& arg)
78     {
79         BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "The equality attribute value relation is not supported", (name));
80         BOOST_LOG_UNREACHABLE_RETURN(filter());
81     }
82     /*!
83      * The callback for inequality relation filter
84      */
on_inequality_relationboost::filter_factory85     virtual filter on_inequality_relation(attribute_name const& name, string_type const& arg)
86     {
87         BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "The inequality attribute value relation is not supported", (name));
88         BOOST_LOG_UNREACHABLE_RETURN(filter());
89     }
90     /*!
91      * The callback for less relation filter
92      */
on_less_relationboost::filter_factory93     virtual filter on_less_relation(attribute_name const& name, string_type const& arg)
94     {
95         BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "The less attribute value relation is not supported", (name));
96         BOOST_LOG_UNREACHABLE_RETURN(filter());
97     }
98     /*!
99      * The callback for greater relation filter
100      */
on_greater_relationboost::filter_factory101     virtual filter on_greater_relation(attribute_name const& name, string_type const& arg)
102     {
103         BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "The greater attribute value relation is not supported", (name));
104         BOOST_LOG_UNREACHABLE_RETURN(filter());
105     }
106     /*!
107      * The callback for less or equal relation filter
108      */
on_less_or_equal_relationboost::filter_factory109     virtual filter on_less_or_equal_relation(attribute_name const& name, string_type const& arg)
110     {
111         BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "The less-or-equal attribute value relation is not supported", (name));
112         BOOST_LOG_UNREACHABLE_RETURN(filter());
113     }
114     /*!
115      * The callback for greater or equal relation filter
116      */
on_greater_or_equal_relationboost::filter_factory117     virtual filter on_greater_or_equal_relation(attribute_name const& name, string_type const& arg)
118     {
119         BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "The greater-or-equal attribute value relation is not supported", (name));
120         BOOST_LOG_UNREACHABLE_RETURN(filter());
121     }
122 
123     /*!
124      * The callback for custom relation filter
125      */
on_custom_relationboost::filter_factory126     virtual filter on_custom_relation(attribute_name const& name, string_type const& rel, string_type const& arg)
127     {
128         BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "The custom attribute value relation \"" + boost::log::aux::to_narrow(rel) + "\" is not supported", (name));
129         BOOST_LOG_UNREACHABLE_RETURN(filter());
130     }
131 
132     BOOST_DELETED_FUNCTION(filter_factory(filter_factory const&))
133     BOOST_DELETED_FUNCTION(filter_factory& operator= (filter_factory const&))
134 };
135 
136 /*!
137  * The base class for filter factories. The class defines default implementations for most
138  * filter expressions. In order to be able to construct filters, the attribute value type must
139  * support reading from a stream. Also, the default filters will rely on relational operators for
140  * the type, so these operators must also be defined.
141  */
142 template< typename CharT, typename AttributeValueT >
143 class basic_filter_factory :
144     public filter_factory< CharT >
145 {
146     //! Base type
147     typedef filter_factory< CharT > base_type;
148 
149 public:
150     //! The type(s) of the attribute value expected
151     typedef AttributeValueT value_type;
152     //  Type imports
153     typedef typename base_type::string_type string_type;
154 
155     /*!
156      * The callback for filter for the attribute existence test
157      */
on_exists_test(attribute_name const & name)158     virtual filter on_exists_test(attribute_name const& name)
159     {
160         return filter(expressions::has_attr< value_type >(name));
161     }
162 
163     /*!
164      * The callback for equality relation filter
165      */
on_equality_relation(attribute_name const & name,string_type const & arg)166     virtual filter on_equality_relation(attribute_name const& name, string_type const& arg)
167     {
168         return filter(expressions::attr< value_type >(name) == parse_argument(arg));
169     }
170     /*!
171      * The callback for inequality relation filter
172      */
on_inequality_relation(attribute_name const & name,string_type const & arg)173     virtual filter on_inequality_relation(attribute_name const& name, string_type const& arg)
174     {
175         return filter(expressions::attr< value_type >(name) != parse_argument(arg));
176     }
177     /*!
178      * The callback for less relation filter
179      */
on_less_relation(attribute_name const & name,string_type const & arg)180     virtual filter on_less_relation(attribute_name const& name, string_type const& arg)
181     {
182         return filter(expressions::attr< value_type >(name) < parse_argument(arg));
183     }
184     /*!
185      * The callback for greater relation filter
186      */
on_greater_relation(attribute_name const & name,string_type const & arg)187     virtual filter on_greater_relation(attribute_name const& name, string_type const& arg)
188     {
189         return filter(expressions::attr< value_type >(name) > parse_argument(arg));
190     }
191     /*!
192      * The callback for less or equal relation filter
193      */
on_less_or_equal_relation(attribute_name const & name,string_type const & arg)194     virtual filter on_less_or_equal_relation(attribute_name const& name, string_type const& arg)
195     {
196         return filter(expressions::attr< value_type >(name) <= parse_argument(arg));
197     }
198     /*!
199      * The callback for greater or equal relation filter
200      */
on_greater_or_equal_relation(attribute_name const & name,string_type const & arg)201     virtual filter on_greater_or_equal_relation(attribute_name const& name, string_type const& arg)
202     {
203         return filter(expressions::attr< value_type >(name) >= parse_argument(arg));
204     }
205 
206     /*!
207      * The callback for custom relation filter
208      */
on_custom_relation(attribute_name const & name,string_type const & rel,string_type const & arg)209     virtual filter on_custom_relation(attribute_name const& name, string_type const& rel, string_type const& arg)
210     {
211         BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "The custom attribute value relation \"" + boost::log::aux::to_narrow(rel) + "\" is not supported", (name));
212         BOOST_LOG_UNREACHABLE_RETURN(filter());
213     }
214 
215     /*!
216      * The function parses the argument value for a binary relation
217      */
parse_argument(string_type const & arg)218     virtual value_type parse_argument(string_type const& arg)
219     {
220         return boost::lexical_cast< value_type >(arg);
221     }
222 };
223 
224 /*!
225  * The function registers a filter factory object for the specified attribute name. The factory will be
226  * used to construct a filter during parsing the filter string.
227  *
228  * \pre <tt>name != NULL && factory != NULL</tt>, <tt>name</tt> points to a zero-terminated string
229  * \param name Attribute name to associate the factory with
230  * \param factory The filter factory
231  */
232 template< typename CharT >
233 BOOST_LOG_SETUP_API void register_filter_factory(
234     attribute_name const& name, shared_ptr< filter_factory< CharT > > const& factory);
235 
236 /*!
237  * The function registers a filter factory object for the specified attribute name. The factory will be
238  * used to construct a filter during parsing the filter string.
239  *
240  * \pre <tt>name != NULL && factory != NULL</tt>, <tt>name</tt> points to a zero-terminated string
241  * \param name Attribute name to associate the factory with
242  * \param factory The filter factory
243  */
244 template< typename FactoryT >
245 inline typename boost::enable_if_c<
246     is_base_and_derived< filter_factory< typename FactoryT::char_type >, FactoryT >::value
register_filter_factory(attribute_name const & name,shared_ptr<FactoryT> const & factory)247 >::type register_filter_factory(attribute_name const& name, shared_ptr< FactoryT > const& factory)
248 {
249     typedef filter_factory< typename FactoryT::char_type > factory_base;
250     register_filter_factory(name, boost::static_pointer_cast< factory_base >(factory));
251 }
252 
253 /*!
254  * The function registers a simple filter factory object for the specified attribute name. The factory will
255  * support attribute values of type \c AttributeValueT, which must support all relation operations, such as
256  * equality comparison and less/greater ordering, and also extraction from stream.
257  *
258  * \pre <tt>name != NULL</tt>, <tt>name</tt> points to a zero-terminated string
259  * \param name Attribute name to associate the factory with
260  */
261 template< typename AttributeValueT, typename CharT >
register_simple_filter_factory(attribute_name const & name)262 inline void register_simple_filter_factory(attribute_name const& name)
263 {
264     shared_ptr< filter_factory< CharT > > factory =
265         boost::make_shared< basic_filter_factory< CharT, AttributeValueT > >();
266     register_filter_factory(name, factory);
267 }
268 
269 /*!
270  * The function registers a simple filter factory object for the specified attribute name. The factory will
271  * support attribute values of type \c AttributeValueT, which must support all relation operations, such as
272  * equality comparison and less/greater ordering, and also extraction from stream.
273  *
274  * \pre <tt>name != NULL</tt>, <tt>name</tt> points to a zero-terminated string
275  * \param name Attribute name to associate the factory with
276  */
277 template< typename AttributeValueT >
register_simple_filter_factory(attribute_name const & name)278 inline void register_simple_filter_factory(attribute_name const& name)
279 {
280     register_simple_filter_factory< AttributeValueT, char >(name);
281 }
282 
283 /*!
284  * The function registers a simple filter factory object for the specified attribute keyword. The factory will
285  * support attribute values described by the keyword. The values must support all relation operations, such as
286  * equality comparison and less/greater ordering, and also extraction from stream.
287  *
288  * \pre <tt>name != NULL</tt>, <tt>name</tt> points to a zero-terminated string
289  * \param keyword Attribute keyword to associate the factory with
290  */
291 template< typename CharT, typename DescriptorT, template< typename > class ActorT >
register_simple_filter_factory(expressions::attribute_keyword<DescriptorT,ActorT> const & keyword)292 inline void register_simple_filter_factory(expressions::attribute_keyword< DescriptorT, ActorT > const& keyword)
293 {
294     register_simple_filter_factory< typename DescriptorT::value_type, CharT >(keyword.get_name());
295 }
296 
297 /*!
298  * The function parses a filter from the sequence of characters
299  *
300  * \pre <tt>begin <= end</tt>, both pointers must not be \c NULL
301  * \param begin Pointer to the first character of the sequence
302  * \param end Pointer to the after-the-last character of the sequence
303  * \return A function object that can be used as a filter.
304  *
305  * \b Throws: An <tt>std::exception</tt>-based exception, if a filter cannot be recognized in the character sequence.
306  */
307 template< typename CharT >
308 BOOST_LOG_SETUP_API filter parse_filter(const CharT* begin, const CharT* end);
309 
310 /*!
311  * The function parses a filter from the string
312  *
313  * \param str A string that contains filter description
314  * \return A function object that can be used as a filter.
315  *
316  * \b Throws: An <tt>std::exception</tt>-based exception, if a filter cannot be recognized in the character sequence.
317  */
318 template< typename CharT, typename TraitsT, typename AllocatorT >
parse_filter(std::basic_string<CharT,TraitsT,AllocatorT> const & str)319 inline filter parse_filter(std::basic_string< CharT, TraitsT, AllocatorT > const& str)
320 {
321     const CharT* p = str.c_str();
322     return parse_filter(p, p + str.size());
323 }
324 
325 /*!
326  * The function parses a filter from the string
327  *
328  * \pre <tt>str != NULL</tt>, <tt>str</tt> points to a zero-terminated string.
329  * \param str A string that contains filter description.
330  * \return A function object that can be used as a filter.
331  *
332  * \b Throws: An <tt>std::exception</tt>-based exception, if a filter cannot be recognized in the character sequence.
333  */
334 template< typename CharT >
parse_filter(const CharT * str)335 inline filter parse_filter(const CharT* str)
336 {
337     return parse_filter(str, str + std::char_traits< CharT >::length(str));
338 }
339 
340 BOOST_LOG_CLOSE_NAMESPACE // namespace log
341 
342 } // namespace boost
343 
344 #include <boost/log/detail/footer.hpp>
345 
346 #endif // BOOST_LOG_UTILITY_SETUP_FILTER_PARSER_HPP_INCLUDED_
347